Skip to content
튜닝 연습소트 튜닝과 페이징
SORT-069

본사 전광판 숫자가 결제 즉시 바뀌게 된 다음 날부터 점심 결제 저장이 1초를 넘긴다

실전DDL버거374 / 700

상황 ​

본사 운영실의 「오늘 매장별 주문 전광판」은 매장 200곳의 오늘 주문 건수를 띄운다. 예전에는 전광판 프로그램이 1분마다 원장을 세었는데, 운영실이 결제가 끝났는데도 숫자가 늦게 바뀐다고 해서 지난주 금요일 조민우가 REFRESH FAST ON COMMIT 구체화 뷰로 바꾸고 전광판이 10초마다 MV를 읽게 했다. 월요일 점심 피크(11:30 ~ 13:00)에 POS 결제 저장이 평소 0.01초 안팎에서 1 ~ 2초로 늘었다. 박팀장은 세 안을 비교해 하나를 골라 달라고 했다. ㉠ MV를 ON DEMAND로 바꿔 1분마다 빠른 새로 고침을 한다. ㉡ MV를 없애고 전광판이 오늘 주문만 원장에서 센다. ㉢ 매장별 오늘 건수 표를 두고 POS가 결제할 때 함께 UPDATE한다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_NO(PK) · ORD_DT VARCHAR2(8) · ORD_HMS · SHOP_NO 200곳 · 날짜순으로 쌓인다 · 이 문제의 운영일에는 오늘 주문이 13시까지 약 9,000건이다(점심 피크 1분에 300건 남짓)
  • 인덱스 ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS): BLEVEL 2 · 리프 약 3,500블록 · CF 22,223 · 통계 최신
  • SHOP 매장: 200행 · 5블록 · PK (SHOP_NO)
  • MV_SHOP_DAY(지난 금요일): 아래 DDL · 146,000행(730일 × 200곳) · 590블록 · 오라클이 만든 I_SNAP$_MV_SHOP_DAY (ORD_DT, SHOP_NO) 인덱스 · ORD에 MV 로그
  • POS 결제 저장은 ORD 1줄과 ORD_ITEM 1 ~ 4줄을 넣고 카드 승인 뒤 COMMIT한다 · 전광판 PC는 6대

원본 SQL ​

sql
-- 지난주 금요일 조민우
CREATE MATERIALIZED VIEW LOG ON ORD
  WITH ROWID, SEQUENCE (ORD_DT, SHOP_NO) INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW MV_SHOP_DAY
  BUILD IMMEDIATE
  REFRESH FAST ON COMMIT
AS
SELECT ORD_DT, SHOP_NO, COUNT(*) AS ORD_CNT
  FROM ORD
 GROUP BY ORD_DT, SHOP_NO;

-- 전광판 (PC 6대 · 10초마다)
SELECT s.SHOP_NO, s.SHOP_NM, NVL(m.ORD_CNT, 0) AS ORD_CNT
  FROM SHOP s, MV_SHOP_DAY m
 WHERE m.SHOP_NO(+) = s.SHOP_NO
   AND m.ORD_DT(+)  = :today
 ORDER BY s.SHOP_NO

실행계획 학습용 예시 ​

xplan
[POS 결제 저장 한 건 · 점심 피크 평균 (애플리케이션 로그)]
                           지난주 금요일(MV 전)   이번 주 월요일(ON COMMIT MV)
  INSERT ORD                     0.4 ms                 0.6 ms   (MV 로그 1줄 더)
  INSERT ORD_ITEM (2.5줄)        0.9 ms                 0.9 ms
  COMMIT                         3.1 ms             1,240 ms

[AWR · 월요일 11:30 ~ 13:00 · Top 대기]
  enq: JI - contention     waits 24,180 · 평균 0.94초 · DB time의 63%
  log file sync            waits 27,355 · 평균 4ms

[전광판 SQL · MV]
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                     |      1 |        |    200 |00:00:00.01 |      12 |          |
|   1 |  SORT ORDER BY                |                     |      1 |    200 |    200 |00:00:00.01 |      12 |18432  (0)|
|*  2 |   HASH JOIN OUTER             |                     |      1 |    200 |    200 |00:00:00.01 |      12 | 1316K (0)|
|   3 |    TABLE ACCESS FULL          | SHOP                |      1 |    200 |    200 |00:00:00.01 |       5 |          |
|   4 |    MAT_VIEW ACCESS BY INDEX ROWID| MV_SHOP_DAY      |      1 |    200 |    198 |00:00:00.01 |       7 |          |
|*  5 |     INDEX RANGE SCAN          | I_SNAP$_MV_SHOP_DAY |      1 |    200 |    198 |00:00:00.01 |       3 |          |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("M"."SHOP_NO"="S"."SHOP_NO")
   5 - access("M"."ORD_DT"=:TODAY)

문제 ​

  1. 전광판을 MV로 바꾼 뒤 POS 결제 저장의 COMMIT이 3.1ms에서 1,240ms가 된 까닭을 ON COMMIT 새로 고침이 하는 일과 AWR의 대기로 설명하시오.
  2. ㉠, ㉡, ㉢ 세 안을 전광판의 일량, 결제 쪽 비용, 숫자가 늦는 정도, 정합성으로 비교하시오.
  3. 하나를 골라 SQL과 DDL로 쓰고, 고른 근거를 숫자로 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자