Skip to main content

인덱스를 이용한 최적화

UNIQUE SCAN

  • UNIQUE SCAN: 유일한 결과를 보장하는 경우
SELECT * FROM TB_COMPANY_MASTER WHERE LISTING_DT > '1995-01-01' and BIZ_REG_NO = '123-45-67890';
  • BIZ_REG_NO에는 UNIQUE INDEX가 설정되어 있음
  • UNIQUE SCAN으로 ROWID(행 위치)를 찾은 다음, 조건에 맞는 행을 Filter
  • WHERE에서 순서를 바꿔도 동일하게 최적화됨

FULL SCAN

  • 인덱스 전체를 순서대로 스캔
  • 회사 이름 순으로 정렬: 인덱스에 회사 이름이 정렬되어 있으므로 FULL SCAN
SELECT * FROM TB_COMPANY_MASTER ORDER BY COMPANY_NM;
  • 테이블 전체를 보는 경우 회사 이름 순이 아니므로 인덱스를 FULL SCAN하지 않음
SELECT * FROM TB_COMPANY_MASTER;

FAST FULL SCAN

  • 테이블을 스캔하는 것보다 인덱스를 스캔하는 것이 더 빠를 때, 순서 없이 스캔
SELECT BIZ_REG_NO, COMPANY_NM FROM TB_COMPANY_MASTER;
  • BIZ_REG_NOCOMPANY_NM을 각각 인덱스에서 FAST FULL SCAN한 후 JOIN

RANGE SCAN

  • 일정 범위를 인덱스에서 스캔
  • 1980년부터 2000년 사이
SELECT * FROM TB_COMPANY_MASTER
WHERE ESTABLISH_DT BETWEEN TO_DATE('1980', 'YYYY') AND TO_DATE('2000', 'YYYY');
  • 회사 이름이 "(주)"로 시작하는 경우
SELECT * FROM TB_COMPANY_MASTER WHERE COMPANY_NM LIKE '(주)%';
  • 회사 이름이 "자"로 끝나는 경우는 RANGE SCAN을 안함(사전순으로 정렬되어 있으므로)
SELECT * FROM TB_COMPANY_MASTER WHERE COMPANY_NM LIKE '%자';

SKIP SCAN

  • 여러 개의 컬럼으로 이뤄진 COMPOSITE 인덱스에서 두 번째 이후 컬럼으로 검색할 때
  • 첫번째 컬럼 → 두번째 컬럼 순으로 정렬되어 있으므로 건너 뛰면서(SKIP) 스캔
  • FS_TYPEFS_YM이 하나의 인덱스로 되어 있으므로 특정 FS_YM을 찾으면 SKIP 스캔 실행
SELECT * FROM TB_FINANCIAL_STATEMENT WHERE FS_YM = '202312';
  • 특정 FS_TYPE을 찾는 경우에는 RANGE 스캔
SELECT * FROM TB_FINANCIAL_STATEMENT WHERE FS_TYPE = 'ANNUAL';

SARGABLE

  • Search Argument Able의 줄임말로 인덱스를 효과적으로 사용할 수 있는 형태
    • 흔히 "인덱스를 탄다"고 표현
  • Sargable 연산자: =, >, <, >=, <=, BETWEEN, LIKE, IS [NOT] NULL, IN
    • 인덱스의 특정 범위로 한정하는 경우
  • 회사 이름이 흑풍 그룹과 같은 경우(sargable)
SELECT * FROM TB_COMPANY_MASTER WHERE COMPANY_NM = '흑풍그룹';
  • 회사 이름이 흑풍 그룹과 다른 경우(not sargable)
SELECT * FROM TB_COMPANY_MASTER WHERE COMPANY_NM <> '흑풍그룹';

컬럼에 계산

  • 비교할 컬럼에 계산이나 함수를 적용할 경우 not sargable
SELECT * FROM TB_FINANCIAL_STATEMENT WHERE TOTAL_ASSETS * 1.1 > 1000000000000;
  • 비교할 값에 계산을 할 경우 sargable
SELECT * FROM TB_FINANCIAL_STATEMENT WHERE TOTAL_ASSETS > 1000000000000 / 1.1;
  • 설립일자에서 연도만 뽑아서 2000과 비교하는 경우 not sargable
SELECT * FROM TB_COMPANY_MASTER WHERE TO_CHAR(ESTABLISH_DT, 'YYYY') < '2000';
  • 2000을 날짜로 바꿔서 설립 일자와 비교 sargable
SELECT * FROM TB_COMPANY_MASTER WHERE ESTABLISH_DT < TO_DATE('2000', 'YYYY');

함수 기반 인덱스

  • 함수 기반 인덱스가 설정된 경우에는 함수를 적용해도 sargable
SELECT * FROM TB_COMPANY_MASTER WHERE UPPER(COMPANY_ENG_NM) < 'E';
  • 인덱스에 적용된 함수 보는 방법
SELECT INDEX_NAME, COLUMN_EXPRESSION
FROM ALL_IND_EXPRESSIONS
WHERE INDEX_NAME = 'IDX_COMPANY_COMPANY_ENG_NM_UPPER';
  • 함수 기반 인덱스가 설정되어 있지 않으면 not sargable
SELECT * FROM TB_COMPANY_MASTER WHERE LOWER(COMPANY_ENG_NM) < 'e';

UNION을 이용해 인덱스 사용하기

  • OR로 검색을 할 경우 인덱스를 사용하지 못할 수 있음
SELECT * FROM TB_COMPANY_MASTER WHERE COMPANY_NM LIKE '(주)%' OR ESTABLISH_DT > '2000-01-01';
  • 각각 인덱스를 이용해 검색을 하도록 질의한 후, 그 결과를 UNION이나 UNION ALL을 이용하여 합칠 수 있음
    • 단, 여러 번 검색으로 총 검색 비용은 더 높을 수도 있으므로 실행 계획을 비교해볼 것
SELECT * FROM TB_COMPANY_MASTER WHERE COMPANY_NM LIKE '(주)%'
UNION
SELECT * FROM TB_COMPANY_MASTER WHERE ESTABLISH_DT > '2000-01-01';

퀴즈

사용자 정보 입력
퀴즈를 시작하기 전에 이름과 소속을 입력해주세요.

Q&A