날짜 검색 조건을 WITH 절에서 한 번 정의하고 CROSS JOIN으로 가져오는 방식 자체가 문제는 아닙니다. 그러나 CTE가 물질화된 상태에서 선택 조건용 OR·COALESCE 등을 결합하면 날짜 범위 조건이 인덱스 검색 조건으로 구성되지 않아 전체 주문을 읽을 수 있습니다.
BAD: 470.919ms, hit=15698, read=1618
물질화된 조건값에 OR 조건 적용
WITH p AS MATERIALIZED (
SELECT TIMESTAMP '2025-01-25'
AS start_dt
,TIMESTAMP '2025-01-26'
AS end_dt
)
SELECT o.ord_no
,o.ord_dtm
,o.ord_amt
FROM startdbpg.tr_ord o
CROSS JOIN p
WHERE (p.start_dt IS NULL
OR o.ord_dtm >= p.start_dt)
AND (p.end_dt IS NULL
OR o.ord_dtm < p.end_dt)
;
SQL
복사
실행계획 보기
•
MATERIALIZED CTE에서 가져온 날짜값은 외부 SQL 계획 단계에서 단순 상수로 펼쳐지지 않습니다. 여기에 p.start_dt IS NULL OR ... 같은 선택 조건이 더해지면, PostgreSQL이 날짜 범위를 Index Cond로 구성하지 못하고 Join Filter로 처리할 수 있습니다. 이번 실측에서는 주문 730,327건을 모두 읽었습니다.
GOOD: 0.449ms, hit=10
날짜 범위를 직접 비교
WITH p AS MATERIALIZED (
SELECT TIMESTAMP '2025-01-25'
AS start_dt
,TIMESTAMP '2025-01-26'
AS end_dt
)
SELECT o.ord_no
,o.ord_dtm
,o.ord_amt
FROM startdbpg.tr_ord o
CROSS JOIN p
WHERE o.ord_dtm >= p.start_dt
AND o.ord_dtm < p.end_dt
;
SQL
복사
실행계획 보기
•
날짜 검색이 필요한 경우 컬럼을 변형하지 않고 직접 범위 조건으로 비교합니다. CROSS JOIN 및 MATERIALIZED를 그대로 유지해도 ord_dtm >= p.start_dt AND ord_dtm < p.end_dt는 실제로 인덱스 범위 검색에 사용됐습니다.
실제 실행 결과 비교
비교 항목 | BAD | GOOD |
실행계획 | Seq Scan • Join Filter | Index Scan • Index Cond |
주문 테이블 접근 행 수 | 730,327건 | 445건 |
최종 반환 행 수 | 445건 | 445건 |
실행시간(1회 측정) | 470.919ms | 0.449ms |
공유 버퍼 | hit 15,698 / read 1,618 | hit 10 |
실습 테이블은 startdbpg.tr_ord, 날짜 컬럼은 ord_dtm, 사용 가능한 날짜 인덱스는 tr_ord_x51입니다. 위 수치는 Supabase에서 EXPLAIN (ANALYZE, BUFFERS, TIMING OFF)로 실제 확인한 결과이며, 실행시간은 캐시 및 측정 시점의 부하에 따라 달라집니다.
TIP
•
① 시작일·종료일이 선택사항이라면 입력된 조건만 WHERE 절에 포함하도록 SQL을 생성하는 방법을 검토합니다. 무조건 OR, CASE, COALESCE로 모든 조건을 한 SQL에 처리하려 하지 않는 것이 좋습니다.
•
② CTE를 여러 곳에서 참조하면 PostgreSQL이 기본적으로 CTE를 물질화할 수 있습니다. 단순한 날짜값 정의라도 실제 계획에서 CTE Scan이 발생하는지, 검색 조건이 Index Cond인지 Join Filter인지 확인해야 합니다.
•
③ o.ord_dtm::DATE = p.base_dt처럼 검색 컬럼을 변형해도 일반적인 ord_dtm 인덱스 범위 검색이 어려워집니다. 하루 검색이라면 시작 시각 이상, 다음 날 시작 시각 미만으로 비교합니다.
KEY POINT
•
중요: CROSS JOIN 자체가 인덱스 사용을 막는 것은 아닙니다. 이번 사례에서의 차이는 물질화된 조건값과 선택 조건용 OR의 조합입니다. WITH p AS (...)처럼 일반적인 단일 참조 CTE는 인라인화되면서 같은 OR 조건도 단순화해 인덱스를 사용할 수 있었습니다.
정리: WITH 절로 조건값을 공통화하더라도, 그 조건이 원본 테이블의 인덱스 검색 조건으로 전달되는지를 실행계획에서 확인해야 합니다. 단순한 구문 형태보다 Index Cond, Join Filter, 실제 처리 행 수가 판단 기준입니다.
기존 Supabase 스키마를 대상으로 읽기 전용 조회 및 실행계획만 확인했으며, 테이블 구조와 데이터는 변경하지 않았습니다.



