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

점주 앱에서 매장 두 곳을 고르면 오늘 주문이 5천 건 넘게 뜨고 화면이 멈춘다

기초SELECT버거50 / 700

상황 ​

버거 점주 앱의 「오늘 주문」은 점주가 고른 매장의 그날 주문을 시각(시:분)순으로 보여 준다. 매장 하나일 때는 문제가 없었는데, 매장 두 곳을 가진 점주를 위해 개발자가 조건 끝에 OR를 덧붙였다. 그 뒤로 매장 둘을 고르면 주문이 5천 건 넘게 뜨고 화면이 몇 초씩 멈춘다. 개발자는 "매장 하나로 테스트할 때는 결과가 맞았다"고 한다. 아래는 2013-03-15에 SH0012와 SH0057을 골랐을 때다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_NO · ORD_DT VARCHAR2(8) · ORD_HMS · SHOP_NO 'SH0001'(매장 200곳, 매장마다 2년에 약 5,000건, 하루 약 7건) · 주문 일자 순으로 쌓였다
  • 인덱스 ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS) · ORD_X02 (SHOP_NO, ORD_DT): BLEVEL 2 · 통계 최신
  • 2013-03-15 주문: SH0012 7건 · SH0057 8건 · SH0057의 2년 치 주문 5,012건
  • 매장을 하나만 고르면 앱은 :v_shop2에 NULL을 넘긴다

원본 SQL ​

sql
SELECT SHOP_NO, SUBSTR(ORD_HMS, 1, 4) AS hhmi, ORD_NO
  FROM ORD
 WHERE ORD_DT  = :v_dt
   AND SHOP_NO = :v_shop1
    OR SHOP_NO = :v_shop2
 ORDER BY ORD_HMS

실행계획 학습용 예시 ​

xplan
----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name            | Starts | E-Rows | A-Rows | A-Time      | Buffers |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |                 |      1 |        |   5019 | 00:00:00.09 |    5041 |
|   1 |  SORT ORDER BY                          |                 |      1 |   5014 |   5019 | 00:00:00.09 |    5041 |
|   2 |   VIEW                                  | VW_ORE_1C6B3F07 |      1 |   5014 |   5019 | 00:00:00.08 |    5041 |
|   3 |    UNION-ALL                            |                 |      1 |        |   5019 | 00:00:00.08 |    5041 |
|   4 |     TABLE ACCESS BY INDEX ROWID BATCHED | ORD             |      1 |      7 |      7 | 00:00:00.01 |      10 |
|*  5 |      INDEX RANGE SCAN                   | ORD_X02         |      1 |      7 |      7 | 00:00:00.01 |       3 |
|*  6 |     TABLE ACCESS BY INDEX ROWID BATCHED | ORD             |      1 |   5000 |   5012 | 00:00:00.08 |    5031 |
|*  7 |      INDEX RANGE SCAN                   | ORD_X02         |      1 |   5000 |   5012 | 00:00:00.01 |      17 |
----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("SHOP_NO"=:V_SHOP1 AND "ORD_DT"=:V_DT)
   6 - filter((LNNVL("ORD_DT"=:V_DT) OR LNNVL("SHOP_NO"=:V_SHOP1)))
   7 - access("SHOP_NO"=:V_SHOP2)

문제 ​

  1. 매장 두 곳을 골랐을 때 5,019건이 나온 이유를 WHERE 절의 연산자 우선순위와 실행계획의 두 갈래(5번 줄과 7번 줄)로 설명하시오.
  2. 두 매장의 그날 주문만 인덱스로 찾아가도록 SQL을 고치고, 고친 뒤 실행계획에 나타날 연산을 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자