에루샤
erusya
Back-end Developer
Web Geek
Anime Otaku
에루샤 프로필 이미지
개발
백엔드

일일 조회수 변동치 추적을 위한 테이블 설계

게시글 조회수 카운터

데이터베이스 테이블을 이용해 게시글이나 아티클을 구현하다보면 게시글의 조회수를 따로 저장해 두는 경우가 많다.
통상적으로 view, count, hit 등으로 컬럼명을 짓고 게시글 조회 타이밍에 맞추어 이 수치를 1씩 올려두는 방식으로 구현하고 있다.

물론 이렇게 조회수를 올려버리면 정확한 조회에 대한 기록이 안남고 그냥 숫자만 올려주는거기 때문에 크게 의미있는 데이터로써 사용하기엔 좀 아쉽긴 한데, 가볍게 구현해두기 참 좋은 기능이라고 볼 수 있다.

public function showPost($id, Request $request)
{
    $post = Post::find($id);
    $post->increment('hit');
    # 아래처럼 구현해도됨
    // $post->hit += 1;
    // $post->save();
    ...Copy


라라벨의 경우에는 이런 역할을 하는 모델 함수인 increment 가 정의되어있어 이를 사용하면되고 라라벨을 사용하지 않으면  기존 방식처럼 hit + 1 방식으로 구현하면 된다.

이러면 showPost 메소드, 즉 페이지 조회가 발생할때마다 조회수는 1씩 오르게된다.


일일 조회수 변동치 추적

근데 만약에 하루에 조회수가 얼마나 나오는지 알고싶다면 어떻게 추가구현을 해볼 수 있을까?

정식 로직 (ChatGPT)

관련 내용으로 ChatGPT에게 질의하면 아래와 같은 방법을 제시해준다.

1. post_daily_views 테이블을 만들어 페이지 조회가 발생한 게시글의 정보를 테이블에 기록, 그리고 이 테이블을 기반으로 일일 조회수 쿼리.
2. 쿠키나 세션을 이용해서 일별 조회수를 저장, 그리고 이 데이터를 기반으로 일일 조회수 산정.

하지만 위 기능들은 결국 별도의 테이블을 작성해 매번 페이지 조회마다 DB 쓰기를 실행해야하고, 단순히 하루치 조회수만 얻고싶은 나에겐 너무 개발 규모가 큰 기능이었다.

내 목적은 최소한의 수정과 최소한의 코드로 '일일 조회수 변동치'만 얻어내면 되는거기 때문이다.

맞춤형 로직

페이지 "조회"할때마다 일일 조회수를 판독할 수 있는 기준이 필요하고, 그럼 그 데이터를 저장할 컬럼 2개를 생성해 그 컬럼값을 기준으로 어떠한 로직을 구상해볼 수 있다.

우선 테이블에 두가지 컬럼을 추가한다.

ALTER TABLE posts 
ADD COLUMN hit_yesterday INT UNSIGNED DEFAULT 0, 
ADD COLUMN hit_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP();Copy

hit_yesterday 는 일일조회수의 기반이 될 '어제'의 조회수를 저장한다.
hit_timestamphit_yesterday가 정말 '어제'날짜의 기반 데이터인지 판단한다.

페이지 조회가 발생할 때 로직은 아래와 같다.

1. 페이지 조회 시 현재 날짜와 hit_timestamp의 날짜를 비교한다.
    1-a. (날짜가 다르면) 일일 조회수 기준치가 어긋나있는 상태이므로 hit_yesterda 에 현재 hit 값을 넣어주고 hit_timestamp 값을 현재 시간으로 갱신한다.
    1-b. (날짜가 같으면) 이미 일일 조회수 기준치가 맞춰져 있는 상태이므로 아무 작업도 하지 않는다.
2. 페이지 hit 값을 +1 처리한다.

요는 페이지 조회수를 올리기전에 기존 조회수를 기준치로 넣어두고 매번 페이지 조회 시 기준 값이 제대로 오늘 처리한 내용인지만 판단하면 된다는것이다.
매번 쓰기 작업을 하지않고 하루에 딱 한번만 쓰기작업이 이루어지고 나머지는 단순 조회로 처리가 가능하다.

public function showPost($id, Request $request)
{
    $post = Post::find($id);

    if(Carbon::parse($post->hit_timestamp)->toDateString() !== Carbon::today()->toDateString()) {
        $post->update([
            'hit_yesterday' => $post->hit,
            'hit_timestamp' => Carbon::now(),
        ]);
    }
    $post->increment('hit');

    ...Copy

실제 위 로직을 녹여본 케이스이다.
조건문에서 조회수 기준치를 정해둔 날짜가 오늘이 아니면 이를 갱신해주고 아닌경우에는 무시하는 단순한 조건식 코드다.

실제로 데이터 베이스에서는 아래와 같이 데이터가 운용이 될 것이다.

titlehithit_yesterdayhit_timestamp
게시글 제목62552025-02-10 12:12:23

만약에 이런 테이블 레코드가 있다면 위 showPost 메소드가 호출되면 현재일(2025-02-12)과 레코드의 timestamp(2025-02-10)을 비교할 것이다.
둘의 날짜(date)가 다르므로 update 구문이 실행되어 위 테이블 값은 아래 처럼 갱신된다.

titlehithit_yesterdayhit_timestamp
게시글 제목62622025-02-12 10:30:45

이후 게시글 조회수를 1 올린다.
그러면 최종적인 레코드는 아래와 같이 변경될것이다.

titlehithit_yesterdayhit_timestamp
게시글 제목63622025-02-12 10:30:45

이러고 난 이후에 만약에 페이지 조회가 한번 더 이루어지면 이번에는 현재일(2025-02-12)와 레코드의 timestamp(2025-02-12)가 같으므로 hit_yesterday, hit_timestamp 의 갱신이 이루어지지않고 hitincrement 되어 아래와같이 레코드가 갱신될 것이다.

titlehithit_yesterdayhit_timestamp
게시글 제목64622025-02-12 10:30:45

그럼이제 아래 코드처럼 오늘날짜의 timestamp를 가진 레코드의 hithit_yesterday 수치의 변동치를 표현해주면 이게 '일일 조회수'로써의 역할을 하게 될것이다.

<span class="view">{{ number_format($post->hit ?? 0) }}</span>
@if($post->getDate('hit_timestamp', 'Y-m-d') == today()->toDateString())
    <span class="view" style="color: #00c7b3">(+{{ number_format($post->hit - $post->hit_yesterday) }})</span>
@endifCopy

본문 이미지좌측이 총조회수, 우측 괄호가 일일 조회수


결론

물론 조회수 데이터를 더 효율적인 통계로 구현하기위해서는 위에서 지피티가 제안해준대로 조회 데이터를 따로 저장해두면 일일별 조회수를 관리하는게 가능할 정도로 정석 구현이 맞긴하다.

하지만 이를 위해 테이블을 별도로 관리하는게 싫거나 최대한 간단하게 구현을 하고 싶다면 위의 방법도 나쁘진 않을듯 하다.

위의 컨셉을 그대로 응용해 timestamp 값을 일일로 하냐, 주간으로 하냐, 월별로 하냐에 따라서 맞춤형 기간 조회수도 충분히 한 테이블내에서 녹여낼 수 있기 때문이다.

#php #Laravel
0 개의 댓글
백엔드 콜렉션의 다른 글
×