월별 정산 조회 쿼리에서 조건 하나를 '<'에서 '<='로 바꿨을 뿐인데 쿼리 시간이 급격히 증가한 사례를 정리한다.
원인은 옵티마이저의 인덱스 선택이 바뀌면서 "대량 범위 스캔"이 발생했기 때문이다.


테이블

  • T_RECEIPT: 월별 정산 내역(대용량)
  • T_CONTRACT: 계약 내역
  • T_TARGET: 조회 대상 계약 내역(필터 역할)

쿼리

SELECT A.CONTRACT_NO
     , SUM(A.AMOUNT) AS AMOUNT
FROM T_RECEIPT A
JOIN T_CONTRACT B ON A.CONTRACT_NO = B.CONTRACT_NO
WHERE EXISTS (SELECT 1 FROM T_TARGET S WHERE S.CONTRACT_NO = A.CONTRACT_NO)
  AND A.SUM_YYMM <= '202512' -- 여기서 '<' → '<=' 변경
GROUP BY A.CONTRACT_NO;

현상

  • A.SUM_YYMM < '202512'일 떄는 빠름
  • A.SUM_YYMM <= '202512'로 바꾸자 엄청 느려짐

원인(실행계획을 확인해보니 인덱스 선택이 바뀜)

인덱스명 컬럼 특징
INDEX01_RECEIPT (CONTRACT_NO) 계약번호 기반 접근에 유리
INDEX02_RECEIPT (SUM_YYMM, CONTRACT_NO) 월 기준 범위 조건에 유리

 

인덱스 선두 컬럼이 범위 조건이면 별 차이 없을것 같지만, 오히려 스캔 범위가 넓어질수록 인덱스가 오히려 느려질 수 있다.

옵티마이저가 월 선두 인덱스(SUM_YYMM)를 타면 SUM_YYMM가 '202512'라서 과거부터 당월까지 거의 전 구간이 스캔됨

즉 한 글자 변경 → 스캔 범위 증가 + 계획 변경 → "폭망"이 되었다.

해결

드라이빙을 CNTR_NO로 강제(힌트)해서 INDEX01로 타게 했다.

SELECT /*+ INDEX(A INDEX01_RECEIPT) */
       A.CONTRACT_NO
     , SUM(A.AMOUNT) AS AMOUNT
FROM T_RECEIPT A
JOIN T_CONTRACT B ON A.CONTRACT_NO = B.CONTRACT_NO
WHERE EXISTS (SELECT 1 FROM T_TARGET S WHERE S.CONTRACT_NO = A.CONTRACT_NO)
  AND A.SUM_YYMM <= '202512' -- 여기서 '<' → '<=' 변경
GROUP BY A.CONTRACT_NO;

'Database' 카테고리의 다른 글

myql 메모  (0) 2025.06.18
MySQL:ALTER TALBE ADD COLUMN이 오래 걸리는 경우  (0) 2025.05.19
GROUP BY ROLLUP  (0) 2025.04.29
쿼리 숫자형 텍스트 정렬  (0) 2023.11.22
JDBC-8038:Expression is not in a GROUP BY clause.  (0) 2023.11.02

+ Recent posts