테마
본사 메뉴팀의 「메뉴별 판매 매장」 화면은 기간을 고르면 메뉴마다 그 기간에 그 메뉴를 판 매장 이름을 쉼표로 이어 한 칸에 보여 준다. 하루를 고르면 '강남구청점,교대점,교대점,…'처럼 같은 매장이 여러 번 나오고, 한 달을 고르면 ORA-01489: result of string concatenation is too long으로 멈춘다. 메뉴팀은 월 단위로 보려고 만든 화면이라 지금은 쓸 수 없다고 한다.
고칠 안이 셋 올라왔다. 개발자는 (가) LISTAGG(DISTINCT …)로 바꾸자고 하고, 운영 DBA는 (나) MAX_STRING_SIZE를 EXTENDED로 바꿔 문자열 한도를 32,767바이트로 늘리자고 한다. 조민우는 (다) 먼저 (메뉴, 매장)으로 줄인 뒤 이어 붙이고 ON OVERFLOW TRUNCATE를 덧붙이자고 한다. 박팀장은 셋을 결과, 일량, 부작용으로 견주어 하나를 고르라고 했다.
ORD 주문: 1,000,000행 · 22,422블록 · ORD_NO · ORD_DT VARCHAR2(8) · SHOP_NO · 인덱스 ORD_X01 (ORD_DT, ORD_HMS) · 2013년 12월 주문 41,540건, 2013-12-30 하루 1,344건ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID)(리프 약 5,520블록) · 12월 주문상품 103,251줄, 12월 30일 3,306줄SHOP 매장: 200행 · 5블록 · SHOP_NM VARCHAR2(100) · 이름은 9 ~ 30바이트(평균 11.4바이트, 200곳을 쉼표로 다 이으면 약 2,500바이트) · 서로 다른 매장 SH0070과 SH0089의 이름이 둘 다 '여의도점'이다ITEM 상품: 92행 · 5블록 · 12월에는 92개 메뉴가 모두 팔렸고, 메뉴마다 196 ~ 200곳의 매장에서 팔렸다MAX_STRING_SIZE는 STANDARD(SQL의 VARCHAR2 한도 4,000바이트)다. 통계는 최신이다.SELECT i.ITEM_ID, m.ITEM_NM,
LISTAGG(s.SHOP_NM, ',') WITHIN GROUP (ORDER BY s.SHOP_NM) AS SHOP_LIST
FROM ORD o, ORD_ITEM i, SHOP s, ITEM m
WHERE o.ORD_DT BETWEEN :d_from AND :d_to
AND i.ORD_NO = o.ORD_NO
AND s.SHOP_NO = o.SHOP_NO
AND m.ITEM_ID = i.ITEM_ID
GROUP BY i.ITEM_ID, m.ITEM_NM
ORDER BY i.ITEM_ID
[하루 · :d_from = :d_to = '20131230']
------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 92 |00:00:00.12 | 5676 | | | |
| 1 | SORT GROUP BY | | 1 | 3381 | 92 |00:00:00.12 | 5676 | 372K| 372K| 330K (0)|
|* 2 | FILTER | | 1 | | 3306 |00:00:00.12 | 5676 | | | |
|* 3 | HASH JOIN | | 1 | 3381 | 3306 |00:00:00.12 | 5676 | 1355K| 1355K| 1702K (0)|
| 4 | TABLE ACCESS FULL | ITEM | 1 | 92 | 92 |00:00:00.01 | 6 | | | |
|* 5 | HASH JOIN | | 1 | 3381 | 3306 |00:00:00.12 | 5670 | 1506K| 1506K| 1364K (0)|
|* 6 | HASH JOIN | | 1 | 1370 | 1344 |00:00:00.01 | 46 | 1449K| 1449K| 1717K (0)|
| 7 | TABLE ACCESS FULL | SHOP | 1 | 200 | 200 |00:00:00.01 | 6 | | | |
| 8 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD | 1 | 1370 | 1344 |00:00:00.01 | 40 | | | |
|* 9 | INDEX RANGE SCAN | ORD_X01 | 1 | 1370 | 1344 |00:00:00.01 | 8 | | | |
| 10 | INDEX FAST FULL SCAN | ORD_ITEM_PK | 1 | 2472K| 2472K|00:00:00.16 | 5624 | | | |
------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:D_FROM<=:D_TO)
3 - access("M"."ITEM_ID"="I"."ITEM_ID")
5 - access("I"."ORD_NO"="O"."ORD_NO")
6 - access("S"."SHOP_NO"="O"."SHOP_NO")
9 - access("O"."ORD_DT">=:D_FROM AND "O"."ORD_DT"<=:D_TO)
[화면 · 하루] 1 한우불고기버거 | 강남구청점,경복궁점,교대점,교대점,구로디지털단지점,구리점,… (메뉴당 평균 36줄, 가장 긴 칸 636바이트)
[한 달 · 2013-12-01 ~ 12-31] ORA-01489 · 3번 줄까지 103,251줄 · 메뉴당 약 1,120줄 × 약 12.4바이트 ≈ 1만 4천 바이트