테마
CS팀의 「주문 관리」 화면은 전체 주문을 최신순(주문번호 역순)으로 한 쪽에 20건씩 보여 주고, 주문마다 고객명과 등급을 함께 띄운다. 상담원은 쪽 번호로 이동한다. 뒤 쪽으로 갈수록 느려진다는 말에 개발자가 시험 삼아 고객명과 등급 칸을 빼 보니 50쪽이 수십 배 빨라졌다. 아래는 칸을 빼기 전, 50쪽(981 ~ 1,000번째)을 열었을 때의 실행계획이다.
T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · 주문번호 순으로 쌓여 PK 순서와 테이블 순서가 같다.M_CUS 고객: 2,000행 · 30블록 · PK_M_CUS (CUS_ID)T_ORD.CUS_ID는 NOT NULL이고, M_CUS로 가는 FK가 켜져 있다. 통계는 최신이다.SELECT *
FROM (SELECT ROWNUM rn, a.*
FROM (SELECT o.ORD_SEQ, o.ORD_DT, o.ORD_ST, o.ORD_AMT, c.CUS_NM, c.CUS_GD
FROM T_ORD o, M_CUS c
WHERE c.CUS_ID = o.CUS_ID
ORDER BY o.ORD_SEQ DESC) a
WHERE ROWNUM <= :page * 20)
WHERE rn > (:page - 1) * 20
[50쪽 · :page = 50]
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.01 | 1033 |
|* 1 | VIEW | | 1 | 1000 | 20 |00:00:00.01 | 1033 |
|* 2 | COUNT STOPKEY | | 1 | | 1000 |00:00:00.01 | 1033 |
| 3 | VIEW | | 1 | 100K| 1000 |00:00:00.01 | 1033 |
| 4 | NESTED LOOPS | | 1 | 100K| 1000 |00:00:00.01 | 1033 |
| 5 | NESTED LOOPS | | 1 | 100K| 1000 |00:00:00.01 | 33 |
| 6 | TABLE ACCESS BY INDEX ROWID | T_ORD | 1 | 100K| 1000 |00:00:00.01 | 12 |
| 7 | INDEX FULL SCAN DESCENDING | PK_T_ORD | 1 | 1000 | 1000 |00:00:00.01 | 3 |
|* 8 | INDEX UNIQUE SCAN | PK_M_CUS | 1000 | 1 | 1000 |00:00:00.01 | 21 |
| 9 | TABLE ACCESS BY INDEX ROWID | M_CUS | 1000 | 1 | 1000 |00:00:00.01 | 1000 |
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN">(:PAGE-1)*20)
2 - filter(ROWNUM<=:PAGE*20)
8 - access("C"."CUS_ID"="O"."CUS_ID")
M_CUS를 몇 번 찾아가는지 실행계획의 Starts로 쓰고, 그중 몇 번이 필요 없는 일인지 설명하시오.