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


