테마
이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.
회계 감사에서 「포인트 원장」 내려받기의 2024년 적립 합계가 point_transactions를 직접 더한 값보다 18,500포인트 적다는 지적이 나왔다. 원인을 찾던 DBA는 SQL의 UNION을 보고 "UNION이 들어간 SQL을 전부 UNION ALL로 바꾸자. 정렬 비용도 준다"라고 제안했다. 지금 UNION을 쓰는 SQL은 아래 셋이다.
박팀장은 SQL마다 바꿔도 되는지, 바꾸면 무엇이 달라지는지 정리해 달라고 했다.
point_transactions: 45,000행 · 210블록 · tx_id(PK) · customer_id · amount · tx_type(EARN · USE · EXPIRE) · created_at · 2024년 9,120건(EARN 5,880 · USE 2,760 · EXPIRE 480) · 이벤트 적립은 배치가 같은 초에 같은 금액(500)으로 한꺼번에 넣는다customers: 5,230행 · 51블록 · reviews: 15,000행 · 775블록 · orders: 34,908행 · 193블록 · status 6가지(PENDING · PAID · SHIPPED · DELIVERED · CANCELLED · RETURNED) · 모두 PK만 있다-- S1 「11월 활동 고객」 마케팅 문자 대상 (리뷰를 썼거나 주문한 고객)
SELECT c.customer_id, c.name, c.email
FROM customers c, reviews r
WHERE r.customer_id = c.customer_id
AND r.created_at >= DATE '2024-11-01' AND r.created_at < DATE '2024-12-01'
UNION
SELECT c.customer_id, c.name, c.email
FROM customers c, orders o
WHERE o.customer_id = c.customer_id
AND o.order_date >= DATE '2024-11-01' AND o.order_date < DATE '2024-12-01';
-- S2 「포인트 원장」 2024년 내려받기 (회계 감사 자료)
SELECT customer_id, created_at, '적립' AS tp, amount FROM point_transactions
WHERE tx_type = 'EARN' AND created_at >= DATE '2024-01-01' AND created_at < DATE '2025-01-01'
UNION
SELECT customer_id, created_at, '사용', amount FROM point_transactions
WHERE tx_type = 'USE' AND created_at >= DATE '2024-01-01' AND created_at < DATE '2025-01-01'
UNION
SELECT customer_id, created_at, '소멸', amount FROM point_transactions
WHERE tx_type = 'EXPIRE' AND created_at >= DATE '2024-01-01' AND created_at < DATE '2025-01-01'
ORDER BY 1, 2;
-- S3 「취소 · 반품 주문」 월 목록
SELECT order_id, customer_id, order_date, status, total_amount FROM orders
WHERE status = 'CANCELLED' AND order_date >= :d1 AND order_date < :d2
UNION
SELECT order_id, customer_id, order_date, status, total_amount FROM orders
WHERE status = 'RETURNED' AND order_date >= :d1 AND order_date < :d2;
[S1]
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 765 | 00:00:00.02 | 1070 |
| 1 | SORT UNIQUE | | 1 | 950 | 765 | 00:00:00.02 | 1070 |
| 2 | UNION-ALL | | 1 | | 988 | 00:00:00.01 | 1070 |
|* 3 | HASH JOIN | | 1 | 250 | 268 | 00:00:00.01 | 826 |
|* 4 | TABLE ACCESS FULL | REVIEWS | 1 | 250 | 268 | 00:00:00.01 | 775 |
| 5 | TABLE ACCESS FULL | CUSTOMERS | 1 | 5230 | 5230 | 00:00:00.01 | 51 |
|* 6 | HASH JOIN | | 1 | 700 | 720 | 00:00:00.01 | 244 |
|* 7 | TABLE ACCESS FULL | ORDERS | 1 | 700 | 720 | 00:00:00.01 | 193 |
| 8 | TABLE ACCESS FULL | CUSTOMERS | 1 | 5230 | 5230 | 00:00:00.01 | 51 |
-----------------------------------------------------------------------------------------------
[S2]
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 9083 | 00:00:00.03 | 630 |
| 1 | SORT UNIQUE | | 1 | 9100 | 9083 | 00:00:00.03 | 630 |
| 2 | UNION-ALL | | 1 | | 9120 | 00:00:00.01 | 630 |
|* 3 | TABLE ACCESS FULL | POINT_TRANSACTIONS | 1 | 5900 | 5880 | 00:00:00.01 | 210 |
|* 4 | TABLE ACCESS FULL | POINT_TRANSACTIONS | 1 | 2700 | 2760 | 00:00:00.01 | 210 |
|* 5 | TABLE ACCESS FULL | POINT_TRANSACTIONS | 1 | 500 | 480 | 00:00:00.01 | 210 |
-------------------------------------------------------------------------------------------------------
[S3 · 2024년 11월]
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 43 | 00:00:00.01 | 386 |
| 1 | SORT UNIQUE | | 1 | 44 | 43 | 00:00:00.01 | 386 |
| 2 | UNION-ALL | | 1 | | 43 | 00:00:00.01 | 386 |
|* 3 | TABLE ACCESS FULL | ORDERS | 1 | 29 | 29 | 00:00:00.01 | 193 |
|* 4 | TABLE ACCESS FULL | ORDERS | 1 | 15 | 14 | 00:00:00.01 | 193 |
-------------------------------------------------------------------------------------------
[S2 대조] 적립 합계: 내려받기 2,921,500 · point_transactions 2,940,000 (차이 18,500)
UNION을 UNION ALL로 바꾸면 SQL마다 결과가 어떻게 달라지는지 판단하시오.