Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

DBDBDEEP

5.3 인덱스를 이용한 Sort 연산 생략 본문

친절한 SQL 튜닝

5.3 인덱스를 이용한 Sort 연산 생략

Kihwane 2026. 5. 18. 11:18

인덱스는 항상 컬럼 순으로 정렬된 상태를 유지한다.

따라서 SQL Order by 또는 Group by 절이 있어도 소트 연산 생략이 가능하다.

* 여기에 Top N 쿼리 특성을 결합하여 온라인 트랜잭션 처리 시스템에서 대량 데이터를 조회할 빠른 응답속도를 있다.

* 또는 특정 조건을 만족하는 최소값 또는 최대값을 찾을 있어 이력 데이터 조회할 매우 유용하다

select 거래일시, 체결건수, 체결수량, 거래대금

from 종목거래

where 종목코드 = ' KR123456 '

order by 거래일시

 

해당 쿼리는 [종목코드 + 거래일시] 순으로 구성하지 않으면 소트연산 생략 불가능

 

 

여기서 SORT ORDER BY 인덱스를 위와 같이 구성하지 않을 나타나고

구성하게 된다면 SORT ORDER BY Operation 생략되게 된다.

TOP N 쿼리 (TOP N StopKey Algorithm)


전체
결과집합 상위 N 레코드만 선택하는 쿼리이다.

 

SQL Server Sybase Top N쿼리를 아래와 같이 작성할 있다.

 

 

 

SELECT TOP 10 거래일시, 체결 건수, 체결 수량, 거래 대금

FROM 종목 거래

WHERE 종목 코드 = 'KR123456'

AND 거래일시 >= '20180304'

ORDER BY 거래일시

 

그러나 오라클에서는 아래처럼 인라인 뷰로 감싸야 한다.

 

SELECT * FROM (

SELECT 거래일시, 체결 건수, 체결 수량, 거래 대금

FROM 종목 거래

WHERE 종목 코드 = 'KR123456'

AND 거래일시 >= '20180304'

ORDER BY 거래일시

)

WHERE  ROWNUM <=10;

 

오라클 쿼리에서 [종목코드 + 거래일시] 순으로 구성된 인덱스를 이용하면

옵티마이저는 소트 연산을 생략하며 아래 그림 처럼 인덱스를 스캔하다가 레코드를 읽는 순간 바로 멈춘다.



 

 

 

실행계획을 보면 Sort Order by Operation 보이지 않고 (인덱스를 구성했기에)
COUNT STOPKEY 눈에 띈다.

이는 조건절에 부합하는 레코드가 아무리 많아도 ROWNUM 으로 지정한 만큼 결과 레코드를 얻으면 거기서 바로 멈춘다는

 

1. 테스트 테이블 생성
CREATE TABLE paging_test (

    id NUMBER PRIMARY KEY,
    name VARCHAR2(100),
    reg_date DATE
);
2. 대용량 데이터 삽입 (1,000,000)

 

BEGIN
  FOR i IN 1 .. 1000 LOOP
    INSERT /*+ APPEND */ INTO paging_test
    SELECT
      (i - 1) * 1000 + LEVEL AS id,
      'USER_' || ((i - 1) * 1000 + LEVEL) AS name,
      SYSDATE - DBMS_RANDOM.VALUE(0, 365)
    FROM dual
    CONNECT BY LEVEL <= 1000;
   
    COMMIT;  -- 주기적인 커밋
  END LOOP;
END;

 

BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(USER, 'PAGING_TEST');
END;
3. OFFSET/FETCH 방식

SELECT *

FROM paging_test
ORDER BY id
OFFSET 5000 ROWS FETCH NEXT 100 ROWS ONLY;

 

 

최소값/최대값 구하기

최소값(MIN) 또는 최대값(MAX) 구하는 실행계획은 아래와 같이 Sort Aggregation 나타난다.

 

전체 데이터를 정렬하진 않지만

전체 데이터를 읽으면서 값을 비교한다고 앞에서 설명하였다.

 

 

여기서 인덱스를 CREATE INDEX EMP_X01 ON EMP(SAL); 같이 구성하면

실행계획은 다음과 같이 바뀐다.

 

 

전체 데이터를 읽지 않고 인덱스를 이용해서 최소,최대 값을 구하려면

조건절 컬럼과 MIN/MAX 함수 인자 컬럼이 모두 인덱스에 포함되어 있어야 한다.



 

 

 



이렇게
구성하면 조건을 만족하는 범위 가장 오른쪽에 있는 하나를 읽는다.

 

실행계획 'FIRST ROW' 조건을 만족하는 레코드 하나를 찾았을 바로 멈춘다는 것을 의미한다.

 

FIRST ROW StopKey 알고리즘이라고 한다.

 

 

인덱스를 [DEPTNO + SAL + MGR] 구성한 경우

 

SELECT MAX(SAL) FROM EMP

WHERE DEPTNO = 30

AND MGR  = 7698;

 

 

여기서도 조건절 컬럼과 MAX 컬럼이 모두 인덱스에 포함되어 있으므로

'First Row StopKey' 알고리즘이 작동한다.

 

MGR 필터조건으로 동작한다.

 

인덱스를 [ SAL + DEPTNO + MGR] 구성한 경우
 

SELECT MAX(SAL) FROM EMP

WHERE DEPTNO = 30

AND MGR  = 7698;

 

DEPTNO MGR 모두 선두컬럼이 아니므로

Index Range Scan 불가하고

Index Full Scan 방식으로 풀리게 된다.

 

 

 

인덱스를 [  DEPTNO + SAL ] 구성한 경우
 

SELECT MAX(SAL) FROM EMP

WHERE DEPTNO = 30

AND MGR  = 7698;

 

DEPTNO=30 만족하는 조건은 바로 찾을 있으므로 MAX(SAL) 쉽게 찾을 있으나

MGR=7698 조건은 테이블에서 필터링 해야만 한다.

 

이럴 때는 전체 레코드를 읽어야 한다.

 

 

'친절한 SQL 튜닝' 카테고리의 다른 글

6.3.2 파티션  (0) 2026.05.18
Union vs. Union All  (0) 2026.05.18
스칼라 서브쿼리 캐싱효과 (장/단점)  (0) 2026.05.18
서브쿼리 언네스팅  (0) 2026.05.18
4.4 서브쿼리  (0) 2026.05.18