SQL 튜닝의 시작 (2013년)
ROWNUM<=1은 항상 빠르지 않다 0 0 97,216

by 구루비스터디 ROWNUM [2018.07.14]


ROWNUM <= 1은 항상 빠르지 않다

  • Where절에 사용된 조건 컬럼에 인덱스가 있고 추출되는 데이터가 많으면 빠르게 수행됨.
  • 하지만 인덱스에서 많은 데이터가 추출되고 나머지 조건 컬럼이 인덱스에 없다면 테이블을 조회하게 되는데,
  • 이때 조건에 해당하는 데이터가 적다면 한건만 추출하더라도 속도가 느릴 수 있다.




-- 테이블 생성
DROP TABLE ROWNUM_T2 PURGE ;

CREATE TABLE rownum_t2
AS
SELECT LEVEL AS c1, CHR(65+MOD(LEVEL,26)) AS c2, LEVEL+99999 AS c3
FROM DUAL
CONNECT BY LEVEL <= 100000 ;

-- 추가 데이터 생성
BEGIN
FOR i IN 1..8 LOOP
INSERT INTO ROWNUM_T2 SELECT * FROM ROWNUM_T2;
COMMIT;
END LOOP;
END;
/

-- 인덱스 생성
CREATE INDEX rownum_t2_idx_01 ON rownum_t2 ( c2 ) ;
CREATE INDEX rownum_t2_idx_03 ON rownum_t2 (c2,c3) ;



-- 테스트[1] 빠른 조회가 되는 경우
(아무 조건이 없거나 인덱스 구성 컬럼만 존재할 때)

-- 아무 조건이 없는 경우

SELECT *
FROM   ROWNUM_T2
WHERE  ROWNUM <= 1 ;

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    29 |   124  (99)| 00:00:02 |
|*  1 |  COUNT STOPKEY     |           |       |       |            |          |
|   2 |   TABLE ACCESS FULL| ROWNUM_T2 |    28M|   799M|   124  (99)| 00:00:02 |
--------------------------------------------------------------------------------

-- 인덱스 구성 컬럼만 존재할 때

SELECT *
FROM   rownum_t2
WHERE  c2 IN ('P', 'S', 'H')
AND    rownum <= 1 ;

--------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |     1 |    29 |     4   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY                |                  |       |       |            |          |
|   2 |   INLIST ITERATOR             |                  |       |       |            |          |
|   3 |    TABLE ACCESS BY INDEX ROWID| ROWNUM_T2        |  3318K|    91M|     4   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | ROWNUM_T2_IDX_01 |   115K|       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------



-- 테스트[2] 느린 조회가 되는 경우(ROWNUM_T2_IDX_01 구성 컬럼은 C2 컬럼임)

SELECT /*+ INDEX(ROWNUM_T2 ROWNUM_T2_IDX_01) */ *
FROM   ROWNUM_T2
WHERE  c2 IN ('P', 'S', 'H')
AND    c1 = 1004
AND    ROWNUM <= 1 ;


선택된 레코드가 없습니다.

경   과: 00:01:30.62

Execution Plan
----------------------------------------------------------
Plan hash value: 4236271276

--------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |     1 |    29 |     7   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY                |                  |       |       |            |          |
|   2 |   INLIST ITERATOR             |                  |       |       |            |          |
|*  3 |    TABLE ACCESS BY INDEX ROWID| ROWNUM_T2        |  2893 | 83897 |     7   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | ROWNUM_T2_IDX_01 |   115K|       |     4   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

-- c2 컬럼이 인덱스 컬럼이므로 인덱스를 읽고 나서 c1 컬럼이 인덱스에 포함되어 있지 않으므로 테이블을 조회하게 된다.
-- c1 컬럼 조건에 해당하는 데이터가 테이블에 많다면 금방 찾을 수 있어서 수행 속도가 빠를 수 있지만,
-- 적다면 테이블을 거의 다 읽고 나서 찾아질 수도 있어서 수행 속도가 느릴 수 있다.


-- 해법 : 새로운 인덱스 생성(인덱스 구성 컬럼 c2 -> c2, c1)

CREATE INDEX rownum_t2_idx_02 ON rownum_t2 ( c2, c1 ) ;

--------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |     1 |    29 |     5   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY                |                  |       |       |            |          |
|   2 |   INLIST ITERATOR             |                  |       |       |            |          |
|   3 |    TABLE ACCESS BY INDEX ROWID| ROWNUM_T2        |  2893 | 83897 |     5   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | ROWNUM_T2_IDX_02 |   463 |       |     4   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------



  • ROWNUM <= 1 조건을 가진 SQL의 성능을 빠르게 수행하기 위해서는 Where 절의 조건에 적절한 인덱스가 구성되어 있어야 한다.
"데이터베이스 스터디모임" 에서 2013년에 "SQL튜닝의시작 " 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/3828

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입