Skip to content
튜닝 연습인덱스 사용 조건
IDX-005

상담원 PC 40대가 10초마다 숫자 하나를 센다

중급SELECT한빛유통05 / 700

상황 ​

고객센터 화면 맨 위의 「미완료 주문」 배지는 완료되지 않은 주문 수를 보여 준다. 상담원 PC 40대가 10초마다 이 숫자를 새로 센다. 처음 판은 NOT IN ('COMPLETE')였다. 느리다는 말이 나오자 조민우는 어디선가 들은 말("부정형은 인덱스를 못 탄다")을 따라 긍정형으로 바꿨다. 그러면서 "혹시 상태가 빈 주문이 있으면 빠질까 봐" 하며 OR ORD_ST IS NULL도 붙였다. 그랬더니 더 느려졌다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_ST COMPLETE 900,000 · PENDING 80,000 · CANCEL 20,000 · NULL 0건(NOT NULL 제약은 없다) · 상태값은 지금 이 셋뿐이다
  • 인덱스 IX_ORD_BIG_ST (ORD_ST): BLEVEL 2 · 리프 2,775블록 · 통계 최신 · ORD_ST에 히스토그램(FREQUENCY)

원본 SQL ​

sql
-- [처음 판]
SELECT COUNT(*) FROM T_ORD_BIG WHERE ORD_ST NOT IN ('COMPLETE');

-- [조민우의 수정안]
SELECT COUNT(*) FROM T_ORD_BIG
 WHERE ORD_ST = 'PENDING' OR ORD_ST = 'CANCEL' OR ORD_ST IS NULL;

실행계획 학습용 예시 · 건수는 적재 스크립트 그대로 ​

xplan
[처음 판 — NOT IN]
-----------------------------------------------------------------------------------------------
| Id  | Operation             | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |               |      1 |        |      1 |00:00:00.04 |    2791 |
|   1 |  SORT AGGREGATE       |               |      1 |      1 |      1 |00:00:00.04 |    2791 |
|*  2 |   INDEX FAST FULL SCAN| IX_ORD_BIG_ST |      1 |    100K|    100K|00:00:00.04 |    2791 |
-----------------------------------------------------------------------------------------------
   2 - filter("ORD_ST"<>'COMPLETE')

[조민우의 수정안 — 긍정형 + OR IS NULL]
-------------------------------------------------------------------------------------------
| Id  | Operation          | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |      1 |        |      1 |00:00:00.06 |    5826 |
|   1 |  SORT AGGREGATE    |           |      1 |      1 |      1 |00:00:00.06 |    5826 |
|*  2 |   TABLE ACCESS FULL| T_ORD_BIG |      1 |    100K|    100K|00:00:00.06 |    5826 |
-------------------------------------------------------------------------------------------
   2 - filter(("ORD_ST"='PENDING' OR "ORD_ST"='CANCEL' OR "ORD_ST" IS NULL))

문제 ​

  1. 처음 판이 인덱스 전체(2,791블록)를 읽는 이유와, 수정안이 더 나빠져 테이블 전체(5,826블록)를 읽는 이유를 설명하시오.
  2. 같은 숫자를 내면서 필요한 범위만 읽도록 SQL을 고치시오. 고친 SQL이 처음 판과 언제나 같은 답을 내는지 NULL, 새 상태값, 중복(UNION ALL로 나눴다면)의 관점에서 따져 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자