본문 바로가기
DB

DB 인덱스

by BIGENGINEER 2026. 7. 14.

인덱스

- 테이블의 데이터를 빠르게 찾기 위해 별도로 만들어 두는 정렬된 자료구조

- 인덱스는 조회 성능을 높이는 대신 저장 공간을 사용하고 INSERT, UPDATE, DELETE 비용을 증가시킴

=> 즉, 조회 성능 높이는 대신 저장 공간 소비하고 데이터 변경 작업 비용을 증가시키는 트레이드오프를 가짐

 

 

인덱스 관리 

- 인덱스는 항상 최신의 정렬 상태를 유지해야 함.

그래서 인덱스가 적용된 컬럼에 INSERT, UPDATE, DELETE가 수행되면 추가적인 연산을 해주어야하고 이로 인해서 오버헤드가 발생함. 

 

[DML 비용 증가]

  • INSERT : 새로운 데이터에 대한 인덱스 추가
  • DELETE : 데이터를 삭제해도 인덱스 공간에서 즉시 지워지지 않고 '사용 안 함' 처리 됨 -> 인덱스 크기는 줄어들지 않음
  • UPDATE : 데이터 수정되면 기존 인덱스 값을 삭제하고 새로운 위치에 인덱스를 생성하는 INSERT+DELETE 동시 발생

 

 

!!! 그래서 효율적인 DB 관리를 위해서는 읽기(조회) 비율이 압도적으로 높은 컬럼에만 인덱스를 생성

쓰기가 빈번한 테이블에는 인덱스를 최소화하는 설계

 

 

 

테이블에 인덱스가 걸려있지 않다면 컬럼 개수가 N개일 때 시간 복잡도 O(N)

테이블에 인덱스가 걸려있다면 시간복잡도 O(logN) -> B-tree 기반 인덱스

 

 

 

 

< 인덱스 사용 이유>

- 특정 조건들을 만족하는 데이터들을 빠르게 찾기 위함

 

 

 

인덱스 만들기 

1. 이미 생성된 테이블에 인덱스 추가

player 테이블
id, name, team_id, backnumber
SELECT * FROM player WHERE name = 'sonny';
SELECT * FROM player WHERE team_id = 105 and backnumber = 7;

 

위의 쿼리에 대해서 각각 인덱스를 만들어보자

 

CREATE INDEX player_name_indx ON player(name); -> 이름에는 동명이인이 있을 수 있으므로 UNIQUE 불

CREATE UNIQUE INDEX team_backnumber_indx ON player(team_id, backnumber);

 

 

 

2. 테이블 생성시 인덱스도 함께 생성 ->  인덱스 이름은 지정 안 해도 자동으로 생성됨 

INDEX player_name_indx (name),

INDEX UNIQUE  team_backnumber_indx (team_id, backnumber)

 

 

 

< 특징 >

1) Multicolumn index/ composite index

-> INDEX UNIQUE team_backnumber_indx (team_id, backnumber) -> 이렇게 컬럼이 여러 개 있는 인덱스 

 

2) primary key에는 index가 자동으로 생성됨 

 

3) 테이블에 걸려있는 인덱스 정보를 알고 싶다면 SHOW INDEX FROM 테이블 명;

이렇게 INDEX NAME이 동일한 경우는 Multicolmn index인 것임

 

 

 


B-tree 기반의 index가 동작하는 방식

 

1) 

B-tree 기반 인덱스

 

a에 대한 인덱스를 생성하면 a에 대한 값들이 정렬이 된 형태로 저장

ptr : 포인터 -> 실제 members 테이블의 어떤 튜플과 연관되어있는지 

 

if) a =9 인 튜플을 찾고 싶다

- 바이너리 서치를 사용 

-> 중간 값을 잡음 -> 5보다 작은 값은 다 버림 -> 중간 값 위쪽의 데이터들에 중간값을 잡음 -> 9를 찾으면

ptr를 활용해서 실제 members 테이블의 튜플을 선택 

 

 

 

2) 

조건이 여러 개인 경우는 full scan을 해야하는 경우가 있음

 

-> 위와 같은 사례를 방지하기 위해서는 a와 b를 하나로 묶은 인덱스가 추가로 필요함 

 

 

 

3)

 

 

CREATE INDEX(a, b)

-> a에 대해서 먼저 정렬하고, a가 같은 값일 경우 b에 대해서 정렬

즉, Multicolumn index로 인덱스를 생성하면 인덱스의 attribute 순서가 중요하다는 점 

 

 

 

4)

 

 

이런 경우에는 성능이 안나옴

=> a를 정렬한 후에 b를 정렬해야되는데 a에 대한 조건이 없고 b가 정렬이 되어있지 않으므로 INDEX(a,b)가 안 쓰이거나, 사용하더라도 성능이 안 나옴

즉, full scan 하는 거랑 거의 동일하거나 혹은 더 안 좋을 수 있음 

 

 

=> 그래서 b에 대해서 인덱스를 따로 만들어줘야 함 

 

 

 

 

[예제]

 

 

아래의 두 쿼리를 만족하는 인덱스는 없음 

세 번째 인덱스를 사용한다고 하더라도 fullscan이 필요함

그리고 마지막 쿼리에서는 OR를 놓치면 안됨 -> OR는 또는 이므로 team_id =110에 대해서는 세 번째 인덱스로 처리할 수 있지만 backnumber =7은 fullscan을 해야됨 

 

 

=> 사용되는 quey에 맞춰서 적절하게 index를 걸어줘야 query가 빠르게 처리될 수 있다. 

 


 

DBMS의 optimizer가 알아서 적절하게 index를 선택

 

내가 직접 index를 고르고 싶다면?

 

1) 가급적 이 인덱스를 사용해 주세요

SELECT * FROM player USE INDEX(backnumber_idx)

WHERE backnumber = 7;

 

2) 이 인덱스를 쓰세요

SELECT * FROM player FORCE INDEX(backnumber_idx)

WHERE backnumber = 7;

 

3) 특정 인덱스 제외시키고 싶을 때는 

IGNORE INDEX 사용

 

 

 

 

그러면 내가 마음대로 막 INDEX 만들어도 되는 거?

- 테이블에 WRITE할 때마다 INDEX도 변경 발생

- 인덱스를 생성하면 인덱스를 위한 데이터도 저장이 되어야 하므로 추가적인 저장 공간이 필요함

 

=> 불필요한 INDEX를 만들지 말자 

 

 

 


 

Covering index

 

team_id와 backnumber를 가져올 건데 두 컬럼은 인덱스 안에 포함되어 있는 multicolumn index임

그러면, team_id =5에 해당하는 값을 찾아서 player 테이블에 가서 찾아올 필요가 없음

왜? 가져오려는 정보가 인덱스 안에 다 포함이 되어있기 때문에 

 

-> 조회하는 attributes를 index가 모두 cover할 때 

-> 조회 성능이 더 빠름 

 

 

 

 

Hash index

1) hash table 사용해서 index 구현 

2) 시간 복잡도 O(1)의 성능

3) rehashing에 대한 부담

=> rehashing : 데이터가 Hash table에 array 형태로 저장되어 있을텐데, 데이터가 쌓이면 hash table을 늘려줘야함

 

4) equality 비교만 가능, range 비교 불가능 -> 즉, = 와 != 만 가능하고 <=와 >= 는 불가

=> 범위를 비교하는 조건으로 튜플을 선택하는 것은 불가능함. 

 

5) multicolumn index의 경우 전체 attributes에 대한 조회만 가능/ 속성 중 일부분만 사용하는 것은 불가

=> B-TREE기반 인덱스인 경우에는 (a, b)가 있을 때 a로만 조회를 하고 싶을 때도 (a, b) 인덱스를 사용할 수 있었는데

hash index에서는 이것이 불가능, (a, b) 모두를 포함하는 조건이어야만 사용 가능 

 

 

 

 

Full scan이 더 좋은 경우

???? 누가 결정 ???? => optimizer

 

 

1) 테이블에 데이터가 조금 있는 경우 : 몇 십 ~ 몇 백

2) 조회하려는 데이터가 테이블의 상당 부분을 차지할 때

=> 만약에 SELECT * FROM customer WHERE mobile_carrier = 'SK';

SK 사용자가 많을 것임 -> 이럴 경우라는 것

 

 

 

 

추가 

1) order by나 group by에도 index가 사용될 수 있다

2) foreign key는 index가 자동으로 생성되지 않을 수 있다 (mysql은 자동 생성)

3) 이미 데이터가 몇 백만 건 이상 있는 테이블에 인덱스를 생성하는 경우에는 DB 성능에 안좋은 영향을 줄 수 있음 

 

 

 

 

 

 

출처 : https://www.youtube.com/watch?v=IMDH4iAQ6zM 쉬운코드