테마
이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.
18화 진단 뒤 정합성 정리 작업에서, 배송 테이블(shipping)로는 배송이 끝났는데 주문(orders.status)은 아직 'SHIPPED'로 남은 주문 2,816건을 바로잡기로 했다. 지금 SQL은 4초 걸린다. 같은 정리를 매일 밤 돌릴 계획이라 개발자가 조인 뷰 UPDATE로 바꿔 보았는데 ORA-01779로 막혔다.
개발자: "설계서에 shipping과 orders는 1:1이라고 적혀 있는데요."
orders: 34,908행 · 193블록 · PK(order_id) · status 6종 · 'SHIPPED' 3,410건shipping: 34,908행 · 183블록 · PK(shipping_id)만 있다 · order_id에는 제약도 인덱스도 없다(설계서상 1:1) · status는 'READY', 'SHIPPED', 'DELIVERED', 'RETURNED'shipping이 'DELIVERED'나 'RETURNED'인 행은 29,870행이다. 정리 대상(주문은 'SHIPPED', 배송은 끝남)은 2,816건이다.DISABLED). 통계는 최신이다.UPDATE orders o
SET o.status = (SELECT s.status FROM shipping s WHERE s.order_id = o.order_id)
WHERE o.status = 'SHIPPED'
AND EXISTS (SELECT 1 FROM shipping s
WHERE s.order_id = o.order_id
AND s.status IN ('DELIVERED', 'RETURNED'));
-- 개발자가 바꿔 본 조인 뷰 → ORA-01779: cannot modify a column which maps to a non key-preserved table
-- UPDATE (SELECT o.status AS o_status, s.status AS s_status
-- FROM orders o, shipping s
-- WHERE s.order_id = o.order_id
-- AND o.status = 'SHIPPED'
-- AND s.status IN ('DELIVERED', 'RETURNED'))
-- SET o_status = s_status;
----------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | 0 |00:00:04.12 | 521K |
| 1 | UPDATE | orders | 1 | | 0 |00:00:04.12 | 521K |
|* 2 | HASH JOIN SEMI | | 1 | 3410 | 2816 |00:00:00.02 | 376 |
|* 3 | TABLE ACCESS FULL | orders | 1 | 5818 | 3410 |00:00:00.01 | 193 |
|* 4 | TABLE ACCESS FULL | shipping | 1 | 29870 | 29870 |00:00:00.01 | 183 |
|* 5 | TABLE ACCESS FULL | shipping | 2816 | 1 | 2816 |00:00:04.08 | 515K |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("S"."ORDER_ID"="O"."ORDER_ID")
3 - filter("O"."STATUS"='SHIPPED')
4 - filter(("S"."STATUS"='DELIVERED' OR "S"."STATUS"='RETURNED'))
5 - filter("S"."ORDER_ID"=:B1)
Starts로 설명하시오.