BAD: 5231.770ms, read=80580
UNION ALL로 반복 집계
SELECT o1.shop_id
,o1.mbr_id
,SUM(o1.ord_amt) AS ord_amt
FROM startdbpg.tr_ord_big o1
WHERE o1.ord_dtm >= '2024-01-01'
AND o1.ord_dtm < '2024-04-01'
GROUP BY o1.shop_id, o1.mbr_id
UNION ALL
SELECT o2.shop_id
,NULL::varchar AS mbr_id
,SUM(o2.ord_amt) AS ord_amt
FROM startdbpg.tr_ord_big o2
WHERE o2.ord_dtm >= '2024-01-01'
AND o2.ord_dtm < '2024-04-01'
GROUP BY o2.shop_id
UNION ALL
SELECT NULL::varchar AS shop_id
,NULL::varchar AS mbr_id
,SUM(o3.ord_amt) AS ord_amt
FROM startdbpg.tr_ord_big o3
WHERE o3.ord_dtm >= '2024-01-01'
AND o3.ord_dtm < '2024-04-01'
;
SQL
복사
실행계획 보기
•
같은 3개월 주문 185만 건을 상세·매장 소계·전체 합계용으로 세 번 읽었습니다(read 26,860 × 3).
GOOD: 2545.676ms, hit=0, read=26860
① GROUPING SETS 등으로 통합 집계
SELECT CASE WHEN GROUPING(o.shop_id) = 1 THEN 'Total'::varchar ELSE o.shop_id END AS shop_id
,CASE WHEN GROUPING(o.mbr_id) = 1 THEN 'Total'::varchar ELSE o.mbr_id END AS mbr_id
,SUM(o.ord_amt) AS ord_amt
FROM startdbpg.tr_ord_big o
WHERE o.ord_dtm >= '2024-01-01'
AND o.ord_dtm < '2024-04-01'
GROUP BY GROUPING SETS ((o.shop_id, o.mbr_id), (o.shop_id), ())
;
SQL
복사
실행계획 보기
•
한 번 읽고 상세·매장 소계·전체 합계를 함께 만듭니다. GROUPING SETS는 필요한 소계 조합을 자유롭게 지정할 수 있습니다.
•
GROUPING(컬럼)은 소계·합계 행에서 1을 돌려줍니다. 그 행에 'Total'을 표시하는 데 씁니다.
② ROLLUP 방식
SELECT CASE WHEN GROUPING(o.shop_id) = 1 THEN 'Total'::varchar ELSE o.shop_id END AS shop_id
,CASE WHEN GROUPING(o.mbr_id) = 1 THEN 'Total'::varchar ELSE o.mbr_id END AS mbr_id
,SUM(o.ord_amt) AS ord_amt
FROM startdbpg.tr_ord_big o
WHERE o.ord_dtm >= '2024-01-01'
AND o.ord_dtm < '2024-04-01'
GROUP BY ROLLUP (o.shop_id, o.mbr_id)
;
SQL
복사
실행계획 보기
•
ROLLUP은 컬럼 순서대로 계층 소계를 만듭니다(매장+회원 → 매장 → 전체). 이 예제는 계층 순서 그대로라 ①과 결과가 같습니다.
KEY POINT
•
UNION ALL로 상세·소계·합계를 따로 집계하면, 같은 데이터를 그 횟수만큼 읽습니다.
•
여러 집계 수준은 ROLLUP이나 GROUPING SETS로 한 번에 구합니다.
•
계층 순서대로 소계가 필요하면 ROLLUP, 원하는 조합만 골라야 하면 GROUPING SETS를 씁니다.
DEEP DIVE — SQL STARTER for MySQL

