Oracle/Tuning2018. 3. 4. 19:55

ORDER BY 절에 여러 테이블의 열을 기술하면 인덱스로 소트를 제거할 수 없다.

 

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

-- 1
DROP TABLE t1 PURGE;
DROP TABLE t2 PURGE;

CREATE TABLE t1 (C1 NUMBER, C2 NUMBER, C3 VARCHAR2(1));
CREATE TABLE t2 (C4 NUMBER, C5 NUMBER, C6 VARCHAR2(1));
CREATE INDEX t1_x1 ON t1 (C1, C2);
CREATE INDEX t2_x1 ON t2 (C4, C5);

INSERT INTO t1 VALUES (1, 1, 'X');
INSERT INTO t1 VALUES (2, 1, 'X');
INSERT INTO t1 VALUES (3, 2, 'X');
INSERT INTO t1 VALUES (4, 2, 'X');
INSERT INTO t2 VALUES (1, 3, 'X');
INSERT INTO t2 VALUES (1, 4, 'X');
INSERT INTO t2 VALUES (2, 1, 'X');
INSERT INTO t2 VALUES (2, 2, 'X');
COMMIT;

 

아래 쿼리는 ORDER BY 절에 여러 테이블의 열이 기술했기 때문에 소트가 발생했다.

-- 2
SELECT   /*+ ORDERED USE_NL(B) INDEX(B) */
         a.c1, a.c2, b.c4, b.c5, a.c3, b.c6
    FROM t1 a
       , t2 b
   WHERE a.c1 >= 1
     AND b.c4 = a.c2
ORDER BY a.c1
       , a.c2
       , b.c5;

C1 C2 C4 C5 C5 C6
-- -- -- -- -- --
 1  1  1  3 X  X
 1  1  1  4 X  X
 2  1  1  3 X  X
 2  1  1  4 X  X
 3  2  2  1 X  X
 3  2  2  2 X  X
 4  2  2  1 X  X
 4  2  2  2 X  X

8 행이 선택되었습니다.

--------------------------------------------------------
| Id  | Operation                              | Name  |
--------------------------------------------------------
|   0 | SELECT STATEMENT                       |       |
|   1 |  SORT ORDER BY                         |       |
|   2 |   NESTED LOOPS                         |       |
|   3 |    NESTED LOOPS                        |       |
|   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T1    |
|*  5 |      INDEX RANGE SCAN                  | T1_X1 |
|*  6 |     INDEX RANGE SCAN                   | T2_X1 |
|   7 |    TABLE ACCESS BY INDEX ROWID         | T2    |
--------------------------------------------------------

 

위 쿼리는 ORDER BY 절을 제거하더라도 정렬된 결과가 반환된다. t1_x1 인덱스가 c1 + c2, t2_x1 인덱스가 c4 + c5로 구성되어 있고, t1.c2 열와 t2.c4 열이 등가 조인되었기 때문에 t1.c1, t1.c2, t2.c5로 정렬된 값이 반환되는 것이다. 정렬 조건과 조인 조건, 인덱스 구성이 맞아 떨어지는 특별한 케이스다.

-- 3
SELECT /*+ ORDERED USE_NL(B) INDEX(B) NO_NLJ_BATCHING(B)
           NO_BATCH_TABLE_ACCESS_BY_ROWID(A)
           NO_BATCH_TABLE_ACCESS_BY_ROWID(B) */
       a.c1, a.c2, b.c4, b.c5, a.c3, b.c6
  FROM t1 a
     , t2 b
 WHERE a.c1 >= 1
   AND b.c4 = a.c2;

C1 C2 C4 C5 C5 C6
-- -- -- -- -- --
 1  1  1  3 X  X
 1  1  1  4 X  X
 2  1  1  3 X  X
 2  1  1  4 X  X
 3  2  2  1 X  X
 3  2  2  2 X  X
 4  2  2  1 X  X
 4  2  2  2 X  X

8 행이 선택되었습니다.

-----------------------------------------------
| Id  | Operation                     | Name  |
-----------------------------------------------
|   0 | SELECT STATEMENT              |       |
|   1 |  TABLE ACCESS BY INDEX ROWID  | T2    |
|   2 |   NESTED LOOPS                |       |
|   3 |    TABLE ACCESS BY INDEX ROWID| T1    |
|*  4 |     INDEX RANGE SCAN          | T1_X1 |
|*  5 |    INDEX RANGE SCAN           | T2_X1 |
-----------------------------------------------


오라클 데이터베이스는 ORDER BY 절에 의한 정렬만 보장한다. 바람직하지는 않지만 성능 개선을 위해 조인 조건과 정렬 순서에 따라 인덱스를 설계하고, ORDER BY 절을 생략해야 하는 경우도 종종 있다.


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

인덱스와 DML 문  (0) 2018.03.06
소트 #3 - IN 절  (0) 2018.03.04
소트 #1 - 정렬 조건  (0) 2018.03.04
블록 그래뉼과 파티션 그래뉼  (0) 2018.03.03
PQ_REPLICATE 힌트  (1) 2018.03.03
Posted by 정희락_