콘텐츠로 건너뛰기

GA4 Intraday 실시간 테이블, 대시보드 원천 데이터로 바로 사용할 수 있을까?

  • 테크

GA4의 빅쿼리(BigQuery) 스트리밍 Export 기능은 당일 유입된 유저의 행동 데이터를 실시간 대시보드에 반영할 수 있는 강력한 솔루션입니다. 하지만 실제 기업의 고도화된 운영 환경(Production)에서 이를 도입하려 할 때, 데이터 엔지니어와 분석가들은 한 가지 본질적인 의문에 직면하게 됩니다. “구글의 정제 과정을 거치지 않은 실시간 테이블(events_intraday)을 가공 없이 대시보드의 원천 데이터로 신뢰해도 될까?”라는 점입니다.

본 글에서는 실제 적재 중인 GA4 빅쿼리 데이터를 기반으로 실시간 테이블의 무결성을 직접 검증(PoC)한 결과와 함께, 데이터 오염을 방지할 수 있는 실무 중심의 SQL 아키텍처를 공유합니다.



1. GA4 빅쿼리 데이터 적재 방식의 이해

실시간 데이터의 자격 여부를 판단하기 위해서는 GA4가 빅쿼리에 데이터를 적재하는 두 가지 테이블의 메커니즘 차이를 먼저 이해해야 합니다.

  • events_YYYYMMDD (Daily 확정 테이블): 하루가 완전히 끝나고 구글 내부의 데이터 가공(무효 트래픽 제거, 지연 데이터 소급 등)이 모두 완료된 후 적재되는 최종 ‘정답지’ 테이블입니다.
  • events_intraday_YYYYMMDD (Intraday 실시간 테이블): 당일 하루 동안 실시간으로 데이터가 지속해서 쌓이는 스트리밍 테이블입니다.

대시보드에서 ‘오늘’의 지표를 실시간으로 모니터링하려면 필연적으로 events_intraday 테이블을 참조해야만 합니다. 그렇다면 이 실시간 테이블의 데이터는 확정 테이블과 비교했을 때 얼마나 높은 정합성을 가질까요?


2. [핵심 검증] Intraday 데이터의 정합성 분석

파이프라인의 신뢰성을 검증하기 위해, 실제 운영 환경의 데이터(2026년 6월 29일 기준)를 바탕으로 구글의 정제가 완료된 확정 테이블과 당일 실시간 테이블을 이벤트명(event_name) 기준으로 1:1 교차 매칭하는 검증 쿼리를 아래와 같이 실행했습니다.

WITH
— ==========================================
— 1. 확정 테이블(Daily) 이벤트 및 유저 수 집계
— ==========================================
daily_events AS (
SELECT
event_name,
COUNT(1) AS confirmed_event_count,
COUNT(DISTINCT user_pseudo_id) AS confirmed_user_count
FROM entrench-consulting.analytics_436013211.events_20260629
GROUP BY event_name
),
— ==========================================
— 2. 실시간 테이블(Intraday) 이벤트 및 유저 수 집계
— ==========================================
intraday_events AS (
SELECT
event_name,
COUNT(1) AS intraday_event_count,
COUNT(DISTINCT user_pseudo_id) AS intraday_user_count
FROM entrench-consulting.analytics_436013211.events_intraday_20260629_BK
GROUP BY event_name
)

— ==========================================
— 3. 확정 vs 실시간 데이터 차이(Diff) 비교
— ==========================================
SELECT
COALESCE(d.event_name, i.event_name) AS event_name,
— 이벤트 건수 비교
COALESCE(d.confirmed_event_count, 0) AS confirmed_event_count,
COALESCE(i.intraday_event_count, 0) AS intraday_event_count,
COALESCE(d.confirmed_event_count, 0) – COALESCE(i.intraday_event_count, 0) AS event_count_diff,
— 유저 수(DAU) 비교
COALESCE(d.confirmed_user_count, 0) AS confirmed_user_count,
COALESCE(i.intraday_user_count, 0) AS intraday_user_count,
COALESCE(d.confirmed_user_count, 0) – COALESCE(i.intraday_user_count, 0) AS user_count_diff

FROM daily_events d
FULL OUTER JOIN intraday_events i ON d.event_name = i.event_name

ORDER BY confirmed_event_count DESC;

데이터 비교 검증 쿼리 예시 (출처: BizSpring)

위 검증 쿼리를 통해 도출된 실제 실행 결과 데이터는 다음과 같습니다.

event_nameconfirmed_event_countintraday_event_countevent_count_diffconfirmed_user_countintraday_user_countuser_count_diff
page_view2121018180
session_start1818018180
first_visit1818018180
exit_test1524-91518-3
experiment_viewed10100990
scroll_down10100330
user_engagement770550

이 실제 검증 결과는 실시간 대시보드 소스로서 Intraday 테이블의 자격을 입증하는 매우 중요한 인사이트를 제공합니다.

  1. 기본 행동 및 유저 지표의 신뢰성 (Diff = 0): 가장 핵심적인 트래픽 지표인 session_start, first_visit, page_view 등은 실시간 테이블과 확정 테이블 간에 오차가 단 1건도 발생하지 않았습니다.
    즉, intraday 테이블만으로 대시보드를 구성해도 활성 사용자 수(DAU)와 기본 페이지뷰 추이는 100% 신뢰할 수 있습니다.
  2. 커스텀 이벤트의 무효 트래픽/중복 필터링 (Diff = -9): 커스텀 이벤트인 exit_test의 경우 실시간 테이블에는 24건이 적재되었으나, 확정 테이블에서는 15건으로 삭감되었습니다. 유저 수 역시 3명이 줄었습니다.
    이는 브라우저 환경에서 특정 태그가 비정상적으로 중복 발송(Double-firing)된 노이즈를 구글의 후처리 배치 프로세스가 찾아내어 정제했음을 보여줍니다.


3. [심층 분석] 이벤트 오차율 8%대, 과연 신뢰해도 될까?

위 검증표를 보면 실시간 데이터와 확정 데이터 사이에 지표 차이가 존재하는 것을 알 수 있습니다.
실제 전체 트래픽 총합을 기준으로 오차율을 계산해 보면 다음과 같습니다.

※ 데이터 정합성 검증 계산 식 (기준: exit_test 노이즈 정제)

  • 실시간 이벤트 총합 (intraday_event_count) : 21 + 18 + 18 + 24 + 10 + 10 + 7 = 108건
  • 확정 이벤트 총합 (confirmed_event_count) : 21 + 18 + 18 + 15 + 10 + 10 + 7 = 99건
  • 정제된 이벤트 수 (event_count_diff 총합) : 108 – 99 = -9건
  • 오차율 계산 : (9/108)*100 = 8.33%

전체 이벤트 건수 기준 약 8.3%의 오차율이 발생한 셈입니다. 단정적으로 보면 “오차율이 너무 높은 것 아닌가?”라는 우려가 들 수 있지만, 여기에는 데이터 엔지니어링 관점의 해석이 필요합니다.

① 모수의 크기에 따른 ‘통계적 착시’

샘플 트래픽의 경우 전체 이벤트 총량이 100여 건 안팎으로 작기 때문에, 태그 중복 발송 같은 단순 에러가 단 몇 건만 발생해도 오차율이 8% 수준으로 크게 널뛰게 됩니다. 그러나 일일 트래픽 총량이 대규모로 늘어나는 일반적인 엔터프라이즈 환경에서 동일한 검증을 진행하면, 이러한 노이즈 오차율은 소수점 단위(1% 미만)로 급격히 감소하며 희석됩니다.
즉, 서비스와 데이터의 모수가 커질수록 실시간 데이터의 전체적인 정합성은 매우 높은 수준으로 수렴하며, 결과적으로 오차는 통계적으로 무시할 수 있는 수준이 됩니다.

② 핵심 비즈니스 지표(User)의 무결성 방어

이벤트 건수에는 다소간의 노이즈(-9건)가 섞였지만, 대시보드에서 가장 민감한 전체 ‘방문자 수(DAU)’ 오차는 ‘0’으로 확인됩니다.(session_start, first_visit 기준)
즉, 사람 수 자체를 부풀리는 치명적인 데이터 오염은 발생하지 않는다는 뜻입니다.

③ 실시간성을 위한 비즈니스적 트레이드오프(Trade-off)

실시간 대시보드의 목적은 ‘어제까지의 완벽한 회계 장부’를 만드는 것이 아닙니다. 당일 집행한 광고 캠페인에 유저들이 즉각 반응하는지, 특정 페이지에 트래픽이 급증하는지와 같은 ‘흐름(Trend)과 이상 징후’를 즉시 포착하는 데 있습니다.
구글의 정제 배치가 끝나기를 하루 종일 기다리느라 골든타임을 놓치는 것보다, 소폭의 노이즈를 감수하더라도 당장의 트렌드를 확인하는 것이 비즈니스적으로 훨씬 가치 있는 선택입니다.


4. [치명적 함정] 지워지지 않은 과거 실시간 테이블

실시간 테이블이 당일 지표용으로는 훌륭한 자격을 갖추고 있지만, 아키텍처 설계 시 절대 간과해서는 안 될 치명적인 함정이 있습니다. 바로 와일드카드(events_intraday_*)를 이용한 무분별한 단순 결합입니다.

구글 공식 문서에는 “확정 테이블이 생성되면 인트라데이 테이블이 자동으로 삭제된다”고 안내되어 있습니다.
그러나 실제 Production 환경을 검증해 보면 과거 특정 일자의 실시간 테이블이 삭제되지 않고 빅쿼리에 그대로 잔존해 있는 현상을 자주 발견할 수 있습니다. 대량의 데이터 처리로 인한 시스템 락(Lock)이나 구글 내부 스토리지 보관 정책에 의해 빈번하게 발생하는 예외 상황입니다.

만약 대시보드 쿼리를 SELECT * FROM events_intraday_* 처럼 와일드카드로만 작성한다면, 대시보드를 열 때마다 삭제되지 않고 방치된 과거의 실시간 찌꺼기 데이터까지 지속해서 오늘 지표에 합산되어 데이터를 심각하게 오염시키게 됩니다.


5. [실무 아키텍처] 조회 기간 격리를 통한 안전한 하이브리드 결합

이러한 리스크를 방지하고 ‘어제까지의 확정 데이터’와 ‘오늘의 실시간 데이터’를 중복 없이 결합하려면, 기준 타임존(Asia/Seoul)을 적용하여 쿼리 실행 시점을 기준으로 조회 범위를 명확히 격리(Isolation)해야 합니다.

— [안전한 아키텍처] 조회 기간 분리를 적용한 하이브리드 결합 쿼리
WITH confirmed_history AS (
— 1. 과거 데이터: 어제까지 정제가 완료된 확정 테이블만 조회
SELECT
_TABLE_SUFFIX AS event_date,
user_pseudo_id,
event_name
FROM `your-project.analytics_xxxx.events_*`
WHERE _TABLE_SUFFIX BETWEEN ‘20260601’ AND FORMAT_DATE(‘%Y%m%d’, DATE_SUB(CURRENT_DATE(‘Asia/Seoul’), INTERVAL 1 DAY))
),

realtime_today AS (
— 2. 당일 데이터: 오직 ‘오늘’ 날짜의 실시간 테이블만 핀셋 타겟팅 (과거 찌꺼기 테이블 간섭 차단)
SELECT
_TABLE_SUFFIX AS event_date,
user_pseudo_id,
event_name
FROM `your-project.analytics_xxxx.events_intraday_*`
WHERE _TABLE_SUFFIX = FORMAT_DATE(‘%Y%m%d’, CURRENT_DATE(‘Asia/Seoul’))
),

combined_data AS (
— 3. 두 레이어 결합 (날짜가 겹치지 않으므로 UNION ALL 사용 가능)
SELECT * FROM confirmed_history
UNION ALL
SELECT * FROM realtime_today
)

— 4. 최종 데이터 집계
SELECT
event_date,
COUNT(1) AS total_events,
COUNT(DISTINCT user_pseudo_id) AS daily_active_users
FROM combined_data
GROUP BY 1
ORDER BY event_date DESC;

쿼리 예시 (출처: BizSpring)


6. [심화 응용] 시간대별 증감 스냅샷과 유저 중복(Double-counting) 방지

대시보드에서 “이전 시간 대비 현재 데이터가 얼마나 증가했는지” 시계열 추이를 시각화하고 싶다면, 매시간 상태를 누적하여 기록하는 ‘스냅샷(Snapshot)’ 데이터 마트를 구축해야 합니다.

이때 데이터 엔지니어들이 가장 많이 범하는 실수가 바로 ‘유저 수 중복 집계(Double-counting)’ 문제입니다. 단순히 시간대별 방문자(HAU)를 구한 뒤 더해버리면, 오후 1시에 온 유저가 3시에 재방문했을 때 하루 누적 방문자가 2명으로 부풀려집니다.

따라서 스냅샷 마트를 설계할 때는 단순 합산(SUM) 방식이 아니라, 매번 당일 전체 누적 기간에 대한 고유 유저 수(COUNT DISTINCT)를 새로 연산하여 기록하는 구조를 취해야 합니다.

Step 1. 매시간 누적 상태 기록 (예약된 쿼리 – WRITE_APPEND)

SELECT
CURRENT_TIMESTAMP() AS snapshot_time,
_TABLE_SUFFIX AS event_date,
COUNT(1) AS cumulative_event_count,
— 전체 누적 기간에 대한 DISTINCT 카운트로 유저 중복 계산 방지
COUNT(DISTINCT user_pseudo_id) AS cumulative_user_count
FROM `your-project.analytics_xxxx.events_intraday_*`
WHERE _TABLE_SUFFIX = FORMAT_DATE(‘%Y%m%d’, CURRENT_DATE(‘Asia/Seoul’))
GROUP BY 1, 2;

쿼리 예시 (출처: BizSpring)

Step 2. 대시보드 뷰(View)에서 순수 증감분 도출

WITH base_snapshot AS (
SELECT snapshot_time, cumulative_event_count, cumulative_user_count
FROM `your-project.my_dataset.hourly_snapshot_mart`
WHERE event_date = FORMAT_DATE(‘%Y%m%d’, CURRENT_DATE(‘Asia/Seoul’))
)

SELECT
snapshot_time,
cumulative_event_count,
cumulative_user_count,
— 이전 시간 스냅샷의 누적치를 차감하여 순수 시간당 증가분(Increment) 도출
cumulative_event_count – LAG(cumulative_event_count) OVER(ORDER BY snapshot_time ASC) AS hourly_new_events,
cumulative_user_count – LAG(cumulative_user_count) OVER(ORDER BY snapshot_time ASC) AS hourly_new_users
FROM base_snapshot
ORDER BY snapshot_time DESC;

쿼리 예시 (출처: BizSpring)



7. 결론

결론부터 말씀드리면, GA4의 events_intraday 테이블은 실시간 대시보드의 원천 데이터로 충분히 믿고 사용할 수 있습니다. 하지만 앞서 살펴본 것처럼, 구글의 데이터 처리 방식이 가진 고유한 한계를 시스템적으로 잘 방어하는 것이 무엇보다 중요합니다.
쿼리 내에서 당일 실시간 데이터만 단독으로 지정해 삭제되지 않은 과거 데이터의 간섭을 원천 차단하고, 스냅샷 적재 시 고유 유저만 카운팅하는 아키텍처를 설계한다면 데이터 오염에 대한 걱정을 덜 수 있습니다

이번 글에서 다룬 데이터 정합성 검증 결과와 하이브리드 결합 쿼리가 여러분의 묵은 고민을 해결하는 데 유용한 힌트가 되기를 바랍니다.


최신 마케팅/고객 데이터 활용 사례를 받아보실 수 있습니다.

비즈스프링 뉴스레터 구독하기 →