Search

[권장:성능]최댓값 조회 상관 서브쿼리

BAD: 236.201ms, hit=107474, read=13229

최댓값을 상관 서브쿼리로 조회
SELECT o.ord_no ,o.mbr_id ,o.ord_dtm FROM startdbpg.tr_ord_big o WHERE o.ord_dtm >= '2024-01-01' AND o.ord_dtm < '2024-01-02' AND o.ord_no = ( SELECT MAX(x.ord_no) FROM startdbpg.tr_ord_big x WHERE x.mbr_id = o.mbr_id AND x.ord_dtm >= '2024-01-01' AND x.ord_dtm < '2024-01-02' ) ;
SQL
복사
실행계획 보기
•
주문 21,708건마다 같은 회원의 그날 주문을 다시 찾아 MAX를 구합니다(loops=21708).
•
같은 테이블을 2만 번 넘게 다시 읽는 셈입니다.

GOOD: 26.650ms, hit=322

ROW_NUMBER로 최신 행 선정
SELECT o.ord_no ,o.mbr_id ,o.ord_dtm FROM ( SELECT o1.ord_no ,o1.mbr_id ,o1.ord_dtm ,ROW_NUMBER() OVER ( PARTITION BY o1.mbr_id ORDER BY o1.ord_no DESC ) AS rn FROM startdbpg.tr_ord_big o1 WHERE o1.ord_dtm >= '2024-01-01' AND o1.ord_dtm < '2024-01-02' ) o WHERE o.rn = 1 ;
SQL
복사
실행계획 보기
•
ROW_NUMBER() OVER (PARTITION BY mbr_id ORDER BY ord_no DESC)는 회원마다 주문번호가 큰 순서로 1, 2, 3… 번호를 매깁니다.
•
하루치 주문을 한 번만 읽고, 회원별 1번만 남깁니다.
💡

KEY POINT

•
그룹별 최댓값 행을 상관 서브쿼리로 찾으면, 행마다 같은 테이블을 다시 읽습니다.
•
그룹별 최신·최대 행은 ROW_NUMBER()로 순위를 매겨 1위만 고릅니다.
•
기준 컬럼에 같은 값(동률)이 있을 수 있으면 RANK()를 씁니다.
✏️

TIP. 동률이 있다면?

•
지금은 기준이 ord_no(유일한 값)라 BAD와 GOOD의 결과가 같습니다. 하지만 ord_dtm처럼 같은 값이 있을 수 있는 컬럼이면, 상관 서브쿼리(= MAX(...))는 동률을 모두 반환하고 ROW_NUMBER는 1건만 고릅니다.
•
동률까지 모두 필요하면 RANK(), 1건만 필요하면 ROW_NUMBER()를 씁니다.
•
ROW_NUMBER로 1건만 고를 때는 ORDER BY ord_dtm DESC, ord_no DESC처럼 유일한 컬럼을 끝에 붙여서 매번 같은 행이 나오게 합니다.
📖 DEEP DIVE — SQL STARTER for MySQL