테마
정산 대시보드의 「기간 고액 주문」 위젯과 같은 이름의 API가 한 문장을 같이 쓴다. 기간(하루 ~ 3년)과 하한 금액을 바인드 변수로 넘기고, 하루 4만 번쯤 실행된다. 지난달 리터럴을 바인드 변수로 바꾼 문장이다.
이번 주 AWR에서 이 문장이 「SQL ordered by Version Count」 1위, 「Parse CPU」 3위에 올랐다. 오전 피크에는 cursor: mutex S 대기도 보인다. 박팀장이 물었다. "바인드로 바꿨으면 커서는 하나여야 하는 것 아닌가요?"
T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT 2022-01-01 ~ 2024-12-31(전부 자정) · ORD_AMTIX_ORD_BIG_DT_AMT (ORD_DT, ORD_AMT): 리프 약 3,320블록 · 6월 한 달이 91블록 · 이 문장이 쓰는 컬럼을 모두 담는다ORD_ST에만 있다 · statistics_level = TYPICAL · 바인드 피킹 켬SELECT COUNT(*) AS ORD_CNT, SUM(ORD_AMT) AS AMT
FROM T_ORD_BIG
WHERE ORD_DT >= :d1
AND ORD_DT < :d2
AND ORD_AMT >= :amt
[V$SQLAREA — 15:00] VERSION_COUNT 43 · LOADS 43 · EXECUTIONS 41,206 · SHARABLE_MEM 2.6MB
[V$SQL — 자식 43개를 계획별로 묶은 것]
PLAN_HASH 계획 자식 수 IS_BIND_AWARE IS_SHAREABLE = Y 실행 BUFFER_GETS/실행
2207145832 INDEX RANGE SCAN IX_ORD_BIG_DT_AMT 38 Y 37 · N 1 6 38,914 61
3519962670 INDEX FAST FULL SCAN (같은 인덱스) 5 Y 5 2 2,292 3,341
[V$SQL_SHARED_CURSOR — Y 칸 세기] BIND_EQUIV_FAILURE 41 · LOAD_OPTIMIZER_STATS 1
[V$SQL_CS_HISTOGRAM — 자식 0] 0:6 1:3 2:0
[V$SQL_CS_SELECTIVITY — 자식 둘만]
CHILD PREDICATE RANGE_ID LOW HIGH
17 >=D1 0 0.175934 0.215030
17 <D2 0 0.749863 0.916499
17 >=AMT 0 0.081052 0.099063
29 >=D1 0 0.623288 0.761796
29 <D2 0 0.893151 1.091629
29 >=AMT 0 0.405000 0.495000
[계획 2207145832 — 한 달 · 하한 10만 원 · 'ALLSTATS LAST']
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 91 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 91 |
|* 2 | FILTER | | 1 | | 2465 |00:00:00.01 | 91 |
|* 3 | INDEX RANGE SCAN| IX_ORD_BIG_DT_AMT | 1 | 2471 | 2465 |00:00:00.01 | 91 |
------------------------------------------------------------------------------------------------------
2 - filter(:D2>:D1)
3 - access("ORD_DT">=:D1 AND "ORD_AMT">=:AMT AND "ORD_DT"<:D2)
filter("ORD_AMT">=:AMT)
[계획 3519962670 — 3년 · 하한 1만 원]
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.09 | 3341 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.09 | 3341 |
|* 2 | FILTER | | 1 | | 450K |00:00:00.08 | 3341 |
|* 3 | INDEX FAST FULL SCAN| IX_ORD_BIG_DT_AMT | 1 | 450K | 450K |00:00:00.06 | 3341 |
------------------------------------------------------------------------------------------------------
2 - filter(:D2>:D1)
3 - filter(("ORD_DT">=:D1 AND "ORD_AMT">=:AMT AND "ORD_DT"<:D2))
[같은 3년을 INDEX RANGE SCAN으로 (힌트)] Buffers 3,322 · 0.08초
V$SQL_CS_HISTOGRAM, V$SQL_CS_SELECTIVITY, V$SQL_SHARED_CURSOR로 설명하시오.