인덱스는 "데이터를 빨리 찾기 위한 목차"이다.
만약 어떤 책에서 목차가 없다면 처음부터 끝까지 읽어서 내가 원하는 부분을 찾아야한다.
반대로 목차가 있는 책이라면?
목차를 보고 바로 내가 원하는 페이지로 이동할 수 있다.
SELECT * FROM USER WHERE NAME = "SONG"
DB가 하는일❕
1. 첫 번째 행 뒤짐
2. 두 번째 행 뒤짐
.
.
.
3. 마지막 행 뒤짐!
➡️ 풀스캔을 한다
CREATE INDEX IDX_USER_NAME ON USER(NAME);
DB가 하는일❕
1. NAME 인덱스에서 SONG을 찾는다
2. 바로 해당 행의 데이터 접근

출처 : https://velog.io/@anrun/efficient-index
별도의 저장공간이 생성되며 B-Tree, Hash, Bitmap과 같은 구조로 컬럼의 값과 물리적 주소를 한쌍으로 저장한다.
인덱스 유형 중 가장 많이 사용하는 것은 B-Tree(균형트리, Balance Tree) 구조이다.

B-Tree 구조는 위와 같이 아무렇게나 나열한 것이 아니라 트리형태로 되어있다.
B-Tree 구조는 중간값을 기준으로 반씩 줄여가면서 찾을 수 있기 때문에 훨씬 빨라진다.
자식이 두개씩 존재하는 이진트리와 달리 B-Tree는 한 노드에 여러 값을 가지기 때문에 성능에 유리하다.
예를 들어 아래와 같은 인덱스가 있다고 하자.
[20 | 40 | 60]
/ | | \
[5 | 10] [25 | 30] [45 | 50] [70 | 80]
여기에서 50을 찾고싶다!
1. 루트 [20 | 40 | 60]을 본다.
2. 50은 40보다 크고 60보다 작음
3. 세 번째 자식으로 이동
4. [45 | 50]에서 찾음
➡️ 한번에 여러 범위를 확확 줄여나갈 수 있음
여기에서 B-Tree는 "균형"트리이다.
따라서 각 노드가 비슷한 밀도를 유지한다.
B-Tree는 “노드 크기 제한 + 절반 유지 규칙”으로 자동 균형을 맞춘다
SELECT *
FROM USER
WHERE USER_ID = 'A123'
SELECT *
FROM ORDER
WHERE ORDER_DATE >= '2026-01-01'
< > <= => BETWEEN 사용 가능
SELECT *
FROM USER
ORDER BY USER_ID
이미 인덱스가 정렬된 상태이기 때문에
DB가 따로 정렬을 하지 않고 읽을 수 있음
정렬 비용 절감 효과 있음!
SELECT *
FROM ORDER A
JOIN USER B
ON A.USER_ID = B.USER_ID
JOIN키에 인덱스가 있다면
JOIN이 엄청 빨라진다.
SELECT *
FROM USER
WHERE UPPER(NAME) = 'SONG'
인덱스는 기본값('SONG')으로 저장되어 있기 때문에
함수를 사용하면 인덱스를 타지 않는다.
WHERE SALARY * 12 > 50000
계산식이 포함되어 있는 인덱스는 인덱스를 타지 못한다!
WHERE NAME LIKE '%ONG'
B-Tree 는 루트->범위찾기 순서로 기능하는데,
앞쪽에 %가 있으면 범위를 찾지 못해 인덱스로 찾지 못한다.
WHERE NAME LIKE 'SON%'
이것은 인덱스를 탈 수 있음
WHERE TO_CHAR(ORDER_DATE,'YYYY') = '2026'
인덱스 못 탐.
좋은 쿼리
WHERE ORDER_DATE >= DATE '2026-01-01'
AND ORDER_DATE < DATE '2027-01-01'
👉 인덱스 사용 가능.
인덱스의 핵심은
1. 인덱스의 위치 찾는다.
2. 실제 테이블 접근
즉 두번 읽는 것이 핵심이다.
SELECT *
FROM USER
WHERE GENDER = 'F';
전체 50% 이상 조회하기 때문에 인덱스 찾고 -> 테이블 왔다갔다 하면서
인덱스를 사용하는 것이 더 느려진다.
SELECT *
FROM ORDER_INFO
WHERE ORDER_ID = '100';
컬럼 많으면 많을수록
-> 테이블 접근 비용 증가
인덱스가 많을 수록
INSERT를 하게되면
인덱스1 수정
인덱스2 수정
.
.
.
모든 인덱스를 수정하게 된다.
쓰기 성능 급격히 저하