Search

[권장:성능]반복 집계를 위한 UNION ALL

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