Oracle/Tuning2018. 3. 4. 22:44

인덱스 선두 칼럼에 IN 절을 사용하면 소트를 제거할 수 없다.

 

테스트를 위해 아래와 같이 테이블을 생성하자.

-- 1
DROP TABLE t1 PURGE;
CREATE TABLE t1 (c1 NUMBER, c2 NUMBER, c3 VARCHAR2 (4000));
CREATE INDEX t1_x1 ON t1 (c1, c2);

INSERT INTO t1 SELECT 1, ROWNUM, LPAD ('X', 4000, 'X') FROM XMLTABLE ('1 to 5');
INSERT INTO t1 SELECT 2, ROWNUM, LPAD ('X', 4000, 'X') FROM XMLTABLE ('1 to 10000');
COMMIT;

 

아래 쿼리는 c1 열에 IN 절을 사용했기 때문에 인덱스로 소트를 회피할 수 없다. 전체 범위로 처리되어 10,031개의 블록 I/O가 발생했다.

-- 2
SELECT c1, c2, LTRIM (c3, 'X') AS c3
  FROM (SELECT   *
            FROM t1
           WHERE c1 IN (1, 2)
        ORDER BY c2)
 WHERE ROWNUM <= 10;

C1 C2 C3
-- -- --
 1  1
 2  1
 1  2
 2  2
 1  3
 2  3
 1  4
 2  4
 1  5
 2  5

10 행이 선택되었습니다.

-------------------------------------------------------------------------------------
| Id  | Operation                               | Name  | Starts | A-Rows | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |       |      1 |     10 |   10031 |
|*  1 |  COUNT STOPKEY                          |       |      1 |     10 |   10031 |
|   2 |   VIEW                                  |       |      1 |     10 |   10031 |
|*  3 |    SORT ORDER BY STOPKEY                |       |      1 |     10 |   10031 |
|   4 |     INLIST ITERATOR                     |       |      1 |  10005 |   10031 |
|   5 |      TABLE ACCESS BY INDEX ROWID BATCHED| T1    |      2 |  10005 |   10031 |
|*  6 |       INDEX RANGE SCAN                  | T1_X1 |      2 |  10005 |      26 |
-------------------------------------------------------------------------------------

 

IN 절의 값 목록이 고정적이라면 아래와 같이 UNION ALL 연산자를 사용하여 성능을 개선할 수 있다. 19개의 I/O를 확인할 수 있다.

-- 3
SELECT c1, c2, LTRIM (c3, 'X') AS c3
  FROM (SELECT   *
            FROM (SELECT *
                    FROM (SELECT * FROM t1 WHERE c1 = 1 ORDER BY c2)
                   WHERE ROWNUM <= 10
                  UNION ALL
                  SELECT *
                    FROM (SELECT * FROM t1 WHERE c1 = 2 ORDER BY c2)
                   WHERE ROWNUM <= 10)
        ORDER BY c2)
 WHERE ROWNUM <= 10;

C1 C2 C3
-- -- --
 1  1
 2  1
 1  2
 2  2
 1  3
 2  3
 1  4
 2  4
 1  5
 2  5

10 행이 선택되었습니다.

--------------------------------------------------------------------------------
| Id  | Operation                          | Name  | Starts | A-Rows | Buffers |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |       |      1 |     10 |      19 |
|*  1 |  COUNT STOPKEY                     |       |      1 |     10 |      19 |
|   2 |   VIEW                             |       |      1 |     10 |      19 |
|*  3 |    SORT ORDER BY STOPKEY           |       |      1 |     10 |      19 |
|   4 |     VIEW                           |       |      1 |     15 |      19 |
|   5 |      UNION-ALL                     |       |      1 |     15 |      19 |
|*  6 |       COUNT STOPKEY                |       |      1 |      5 |       7 |
|   7 |        VIEW                        |       |      1 |      5 |       7 |
|   8 |         TABLE ACCESS BY INDEX ROWID| T1    |      1 |      5 |       7 |
|*  9 |          INDEX RANGE SCAN          | T1_X1 |      1 |      5 |       2 |
|* 10 |       COUNT STOPKEY                |       |      1 |     10 |      12 |
|  11 |        VIEW                        |       |      1 |     10 |      12 |
|  12 |         TABLE ACCESS BY INDEX ROWID| T1    |      1 |     10 |      12 |
|* 13 |          INDEX RANGE SCAN          | T1_X1 |      1 |     10 |       2 |
--------------------------------------------------------------------------------


'Oracle > Tuning' 카테고리의 다른 글

Top-N 쿼리 개선 사례  (0) 2018.03.07
인덱스와 DML 문  (0) 2018.03.06
소트 #2 - 조인 정렬 조건  (0) 2018.03.04
소트 #1 - 정렬 조건  (0) 2018.03.04
블록 그래뉼과 파티션 그래뉼  (0) 2018.03.03
Posted by 정희락_