Skip to content
튜닝 연습서브쿼리와 쿼리 변환
SUBQ-019

쿠폰 대상 400명을 뽑는 조회가 평가 테이블을 2,000번 읽는다

기초SELECT한빛유통254 / 700

상황 ​

CS팀의 「사과 쿠폰 대상」 화면은 상품 평가에 1점을 남긴 고객을 뽑아 쿠폰 대상으로 올린다. 상담원들이 하루 수백 번 새로 고치는데 한 번에 0.3초가 걸린다. SQL을 짠 조민우는 "EXISTS 안에 ROWNUM = 1을 넣어서 한 건만 찾으면 멈추게 했다"라고 한다.

테이블과 인덱스 ​

  • M_CUS 고객: 2,000행 · 30블록 · PK_M_CUS (CUS_ID)
  • T_ITM_EVL 상품평가: 5,000행 · 48블록 · PK_T_ITM_EVL (ITM_ID, EVL_LST_NO)만 있고 CUS_ID 인덱스는 없다
  • 고객 한 명이 평가를 2~3건 남겼고, 한 고객의 평가는 점수가 모두 같다 · 1점 평가 1,000건 · 1점을 남긴 고객 400명
  • 평가는 EVL_LST_NO 순으로 쌓여 있어서, 고객번호가 클수록 그 고객의 첫 평가가 테이블 뒤쪽에 있다 · 통계 최신

원본 SQL ​

sql
SELECT c.CUS_ID, c.CUS_NM, c.CUS_GD
  FROM M_CUS c
 WHERE EXISTS (SELECT 1
                 FROM T_ITM_EVL e
                WHERE e.CUS_ID = c.CUS_ID
                  AND e.EVL_PT = 1
                  AND ROWNUM = 1)          -- 한 건 찾으면 멈추게

실행계획 학습용 예시 ​

xplan
--------------------------------------------------------------------------------------------
| Id  | Operation           | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |           |      1 |        |    400 |00:00:00.31 |   80842 |
|*  1 |  FILTER             |           |      1 |        |    400 |00:00:00.31 |   80842 |
|   2 |   TABLE ACCESS FULL | M_CUS     |      1 |   2000 |   2000 |00:00:00.01 |      30 |
|*  3 |   COUNT STOPKEY     |           |   2000 |        |    400 |00:00:00.30 |   80812 |
|*  4 |    TABLE ACCESS FULL| T_ITM_EVL |   2000 |      1 |    400 |00:00:00.30 |   80812 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter( EXISTS (SELECT 0 FROM "T_ITM_EVL" "E" WHERE ROWNUM=1 AND
              "E"."CUS_ID"=:B1 AND "E"."EVL_PT"=1))
   3 - filter(ROWNUM=1)
   4 - filter(("E"."CUS_ID"=:B1 AND "E"."EVL_PT"=1))

문제 ​

  1. 3번과 4번 줄의 Starts가 2,000인 이유와 80,812블록이 어디서 나오는지 설명하시오. 서브쿼리가 조인으로 펼쳐지지 않은 이유도 설명하시오.
  2. 결과가 바뀌지 않게 SQL을 고치고, 고친 뒤의 처리 방식을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자