성능 개선 · Oracle SQL

대용량 하위 데이터를 먼저 GROUP BY할 때 조회가 느려지는 이유

조회 범위와 무관한 선집계를 제거하고 필요한 주문만 계산하도록 SQL 실행 구조를 바꾼 과정을 정리합니다.

OracleSQL 튜닝MyBatis실행계획

문제

Oracle 11g과 MyBatis를 사용하는 주문조회 화면에서 검색 기간을 하루 단위로 줄여도 응답시간이 거의 줄지 않았다. 화면 조건은 충분히 좁았지만 핵심 Query는 약 40~50초가 걸렸다. 조건 변화가 실행시간에 영향을 주지 않는다는 점에서 화면 렌더링이나 네트워크보다 SQL 내부의 고정 비용을 먼저 의심했다.

실행 환경과 전제

  • 기존 반환 컬럼과 화면 계약을 유지해야 했다.
  • 주문 한 건에는 여러 하위 결과가 연결되고 화면에는 주문별 결과 건수가 필요했다.
  • 개선 효과는 현업이 반복 사용하는 기간·업체·상태 조건에서 검증해야 했다.
  • 실제 테이블·컬럼·인덱스 이름과 업무 데이터는 공개하지 않는다.

확인한 실행 구조

기존 Query는 하위 결과 전체를 주문 단위로 먼저 집계한 뒤 주문 목록과 결합했다. 주문 검색 조건은 바깥 Query에 있었으므로 사용자가 하루치만 조회해도 하위 집계는 전체 범위에서 수행됐다. 실행계획에서 먼저 처리되는 집계의 입력 범위가 줄지 않는 것이 고정 비용의 원인이었다.

아래 코드는 문제 해결 구조를 설명하기 위한 pseudocode이며 실제 클래스·테이블·설정 이름과는 무관합니다.

SELECT ...
FROM ORDER_ITEM item
JOIN (
  SELECT BUSINESS_KEY, COUNT(*)
  FROM ORDER_RESULT
  GROUP BY BUSINESS_KEY
) result_count
  ON result_count.BUSINESS_KEY = item.BUSINESS_KEY
WHERE item.REQUESTED_AT >= :fromDate;

선택한 해결 방법

먼저 조회 대상 주문을 제한하고, 각 주문에 필요한 결과만 계산하도록 상관 서브쿼리 형태로 재구성했다. 전체 선집계를 그대로 둔 채 인덱스만 추가하는 안도 검토했지만, 집계 입력 건수 자체가 줄지 않으면 개선 폭이 제한된다고 판단했다.

아래 코드는 문제 해결 구조를 설명하기 위한 pseudocode이며 실제 클래스·테이블·설정 이름과는 무관합니다.

SELECT item.BUSINESS_KEY,
       (SELECT COUNT(*)
          FROM ORDER_RESULT result
         WHERE result.BUSINESS_KEY = item.BUSINESS_KEY) AS RESULT_COUNT
FROM ORDER_ITEM item
WHERE item.REQUESTED_AT >= :fromDate;

상세 조회에서는 기존 인덱스의 선두 조건과 실제 검색 조건이 맞지 않는 구간을 따로 분리했다. 공개 글에서는 이를 주문 관련 테이블의 `(법인 키, 업무 키)` 복합 인덱스 필요성 도출과 실행계획 보완으로만 설명하며, 실제 인덱스 적용 성과로 확대하지 않는다.

검증

  • 기존 Query와 개선 Query의 결과 건수·반환 값을 조건별로 비교했다.
  • 기간, 업체, 주문 상태 등 실제 사용 빈도가 높은 조건으로 반복 측정했다.
  • 목록 테스트 표 2행은 같은 시나리오를 단계별로 반복한 Y 2행이고, 상세 테스트 표 11행은 Y 7행·N 4행이었다.
  • 이를 13개 고유 시나리오나 전건 성공으로 집계하지 않았다.
  • 확인된 결함을 보완하고 승인·완료 절차를 거쳐 목록 Query 변경만 운영에 반영했다. 상세 Query는 복합 인덱스 필요성을 도출하고 실행계획을 보완한 범위이며, 인덱스 배포 성과로 주장하지 않는다.

운영 반영 결과와 수치의 한계

핵심 Query 응답시간은 약 40~50초에서 약 0.5초로 줄었고, 운영상 전체 조회의 95% 이상이 1초 이내에 처리됐다.

이 수치는 당시 사용자 운영 확인을 기준으로 기록한 값이며, 현재 원본 측정 로그는 보존되어 있지 않다. 따라서 보존된 실측 로그로 재현 가능한 수치처럼 설명하지 않는다.

적용할 때 주의할 점

상관 서브쿼리는 언제나 더 빠른 해법이 아니다. 외부 Query의 결과 건수가 크거나 상관 조건을 지원하는 인덱스가 없다면 반복 접근 비용이 커질 수 있다. 선집계와 주문별 계산 중 어느 쪽이 유리한지는 실제 카디널리티와 조회 패턴으로 판단해야 한다.