Oracle/Tuning2019. 4. 19. 08:26

테이블 전체 건수를 조회하는 방법을 살펴보자.

 

테스트를 위해 아래와 같이 테이블과 인덱스를 생성하자. c1 칼럼은 NOT NULL 제약 조건으로 생성했다. t1_x1 인덱스는 NOT NULL 제약 조건 칼럼이 포함되어 있고, t1_x2 인덱스는 그러지 않다.

-- 1
DROP TABLE t1 PURGE;

CREATE TABLE t1 (c1 NOT NULL, c2, c3) AS
SELECT LPAD ('X',  10, 'X') AS c1
     , LPAD ('X',  10, 'X') AS c2
     , LPAD ('X', 100, 'X') AS c3
  FROM XMLTABLE ('1 to 100000');

CREATE INDEX t1_x1 ON t1 (c1, c2);
CREATE INDEX t1_x2 ON t1 (c2);

 

아래 쿼리는 COUNT (*) 표현식을 사용했다. NOT NULL 칼럼이 포함된 인덱스가 존재하는 경우 크기가 가장 작은 인덱스를 사용하는 실행 계획이 수립된다. t1_x2 인덱스는 t1_x1 인덱스보다 크기가 작지만 널 값을 포함하지 않으므로 테이블 전체 건수를 조회하는데 사용할 수 없다.

-- 2-1
SELECT COUNT (*) FROM t1;

---------------------------------------
| Id  | Operation             | Name  |
---------------------------------------
|   0 | SELECT STATEMENT      |       |
|   1 |  SORT AGGREGATE       |       |
|   2 |   INDEX FAST FULL SCAN| T1_X1 |
---------------------------------------

 

대용량 테이블인 경우 INDEX_FFS 힌트와 PARALLEL_INDEX 힌트를 사용하면 테이블 전체 건수를 빠르게 조회할 수 있다.

-- 2-2
SELECT /*+ INDEX_FFS(T1) PARALLEL_INDEX(T1 4) */ COUNT (*) FROM t1;

----------------------------------------------
| Id  | Operation                 | Name     |
----------------------------------------------
|   0 | SELECT STATEMENT          |          |
|   1 |  SORT AGGREGATE           |          |
|   2 |   PX COORDINATOR          |          |
|   3 |    PX SEND QC (RANDOM)    | :TQ10000 |
|   4 |     SORT AGGREGATE        |          |
|   5 |      PX BLOCK ITERATOR    |          |
|*  6 |       INDEX FAST FULL SCAN| T1_X1    |
----------------------------------------------

 

t1_x1 인덱스를 삭제해보자.

-- 3
DROP INDEX t1_x1;

인덱스가 삭제되었습니다.

 

2-1번 쿼리를 다시 수행해보면 테이블을 FULL SCAN하는 것을 확인할 수 있다. 사용할 수 있는 인덱스가 없기 때문이다.

-- 4-1
SELECT COUNT (*) FROM t1;

-----------------------------------
| Id  | Operation          | Name |
-----------------------------------
|   0 | SELECT STATEMENT   |      |
|   1 |  SORT AGGREGATE    |      |
|   2 |   TABLE ACCESS FULL| T1   |
-----------------------------------

 

이런 경우에는 FULL 힌트와 PARALLEL 힌트를 사용해야 한다.

-- 4-2
SELECT /*+ FULL(T1) PARALLEL(T1 4) */ COUNT (*) FROM t1;

-------------------------------------------
| Id  | Operation              | Name     |
-------------------------------------------
|   0 | SELECT STATEMENT       |          |
|   1 |  SORT AGGREGATE        |          |
|   2 |   PX COORDINATOR       |          |
|   3 |    PX SEND QC (RANDOM) | :TQ10000 |
|   4 |     SORT AGGREGATE     |          |
|   5 |      PX BLOCK ITERATOR |          |
|*  6 |       TABLE ACCESS FULL| T1       |
-------------------------------------------

 

NOT NULL 칼럼이 포함된 인덱스의 존재 여부에 따라 힌트를 달리 기술하는 것은 번거로운 일이다. 이런 경우 아래와 같은 힌트를 사용할 수 있다. 모순되는 힌트지만 특수한 경우로 이해하자.

-- 5
SELECT /*+ INDEX_FFS(T1) PARALLEL_INDEX(T1 4) FULL(T1) PARALLEL(T1 4) */ COUNT (*) FROM t1;

-------------------------------------------
| Id  | Operation              | Name     |
-------------------------------------------
|   0 | SELECT STATEMENT       |          |
|   1 |  SORT AGGREGATE        |          |
|   2 |   PX COORDINATOR       |          |
|   3 |    PX SEND QC (RANDOM) | :TQ10000 |
|   4 |     SORT AGGREGATE     |          |
|   5 |      PX BLOCK ITERATOR |          |
|*  6 |       TABLE ACCESS FULL| T1       |
-------------------------------------------

 

t1_x1 인덱스를 다시 생성해보자.

-- 6
CREATE INDEX t1_x1 ON t1 (c1, c2);

인덱스가 생성되었습니다.

 

쿼리를 다시 수행하면 T1_X1 인덱스를 FFS하는 것을 확인할 수 있다.

-- 7
SELECT /*+ INDEX_FFS(T1) PARALLEL_INDEX(T1 4) FULL(T1) PARALLEL(T1 4) */ COUNT (*) FROM t1;

----------------------------------------------
| Id  | Operation                 | Name     |
----------------------------------------------
|   0 | SELECT STATEMENT          |          |
|   1 |  SORT AGGREGATE           |          |
|   2 |   PX COORDINATOR          |          |
|   3 |    PX SEND QC (RANDOM)    | :TQ10000 |
|   4 |     SORT AGGREGATE        |          |
|   5 |      PX BLOCK ITERATOR    |          |
|*  6 |       INDEX FAST FULL SCAN| T1_X1    |
----------------------------------------------
Posted by 정희락_