① 특정일 조회
BAD: 8433.907ms, hit=13602, read=336955
원본 날짜 컬럼에 TO_CHAR 적용
SELECT o.ord_no ,o.ord_dtm
FROM startdbpg.tr_ord_big o
WHERE TO_CHAR(o.ord_dtm, 'YYYYMMDD') = '20240101'
;
SQL
복사
실행계획 보기
•
TO_CHAR로 날짜 컬럼을 변형해 인덱스를 쓰지 못합니다.
•
테이블 전체 약 2,600만 건을 읽고, 그중 2만여 건만 남깁니다(Seq Scan).
GOOD: 6.395ms, hit=325
날짜 범위 조건 사용
SELECT o.ord_no ,o.ord_dtm
FROM startdbpg.tr_ord_big o
WHERE o.ord_dtm >= DATE '2024-01-01'
AND o.ord_dtm < DATE '2024-01-02'
;
SQL
복사
실행계획 보기
•
날짜 컬럼은 그대로 두고 시작일 이상·다음 날 미만으로 범위를 지정해 tr_ord_big_x40 인덱스로 조회합니다.
② 회원 ID 조회
BAD: 12.205ms, hit=1252
원본 컬럼에 LOWER 적용
SELECT m.mbr_id ,m.nick_nm
FROM startdbpg.ms_mbr_big m
WHERE LOWER(m.mbr_id) = 'm00001'
;
SQL
복사
실행계획 보기
•
LOWER로 원본 컬럼을 변형해 인덱스를 쓰지 못합니다.
•
회원 약 10만 건을 모두 읽고, 1건만 남깁니다(Seq Scan).
GOOD: 0.096ms, hit=3
조건값에 UPPER 적용
SELECT m.mbr_id ,m.nick_nm
FROM startdbpg.ms_mbr_big m
WHERE m.mbr_id = UPPER('m00001')
;
SQL
복사
실행계획 보기
•
컬럼은 그대로 두고 조건값에 UPPER를 적용해 인덱스로 찾습니다.
•
mbr_id가 항상 대문자로 저장된다는 전제에서만 두 SQL의 결과가 같습니다.③ 기준 시각 1시간 전부터 조회
BAD: 1326.509ms, hit=13395, read=337162
원본 컬럼에 계산 처리
SELECT o.ord_no ,o.ord_dtm
FROM startdbpg.tr_ord_big o
WHERE o.ord_dtm + INTERVAL '1 hour'
>= TIMESTAMP '2025-01-25 11:00:00'
;
SQL
복사
실행계획 보기
•
+ INTERVAL '1 hour'처럼 원본 컬럼에 계산을 적용해 인덱스를 쓰지 못합니다.
•
약 2,600만 건을 읽고, 72건만 남깁니다(Seq Scan).
GOOD: 0.149ms, hit=5
조건값에 계산 처리
SELECT o.ord_no ,o.ord_dtm
FROM startdbpg.tr_ord_big o
WHERE o.ord_dtm >= TIMESTAMP '2025-01-25 11:00:00'
- INTERVAL '1 hour'
;
SQL
복사
실행계획 보기
•
1시간 계산을 조건값으로 옮겨 원본 ord_dtm을 인덱스 조건으로 사용하여 데이터를 검색합니다.
KEY POINT
•
WHERE 절의 컬럼에 함수나 계산을 적용하면 인덱스를 제대로 쓰지 못합니다. (TO_CHAR, LOWER, + INTERVAL 등)
•
컬럼은 그대로 두고, 변환과 계산은 조건값 쪽에 적용합니다.
•
실행계획에서 조건이 Index Cond에 보이면 인덱스로 찾은 것이고, Filter에만 보이면 다 읽은 뒤 걸러낸 것입니다.
TIP
•
함수 기반 인덱스로 해결할 수도 있지만 차선책일 뿐입니다. 먼저 컬럼 변형을 없앨 수 있는지 확인합니다.
•
PostgreSQL에서는 TO_CHAR로 함수 기반 인덱스를 만들 수도 없습니다.
DEEP DIVE — SQL TUNER for PostgreSQL 기본원리편


