Search

DB인덱스

순서
1
사람
상태
Done
태그
DB
날짜
2024/10/12
실무에서 DB테이블을 요청할 때 인덱스를 추가해 달라는 말을 많이 들었습니다.
인덱스를 추가할 때 어떤 기준으로 어떻게 추가하면 좋은지, 그리고 인덱스를 왜 걸어야 되는지에 대하여 설명하도록 하겠습니다.
보통 My-SQL 기준으로 인덱스는 B트리 기반으로 작동하고 있습니다.
이유는 아래와 같습니다.

인덱스로 B-Tree를 사용하는 이유

1. 트리의 높이가 낮다
B-tree는 한 노드에 여러 키와 자식 노드를 가질 수 있어서, 같은 양의 데이터를 저장할 때 이진 트리보다 트리의 높이가 낮습니다.
예를 들어, 100만 개의 데이터를 저장할 때:
이진 트리는 높이가 최대 20 정도 됩니다.
B-tree는 높이가 최대 3 정도밖에 되지 않습니다.
이렇게 높이가 낮으면 데이터를 찾거나 추가하고 삭제하는 데 시간이 덜 걸립니다.
책장에 책을 꽂을 때, 한 칸에 책을 하나만 놓는 게 아니라 여러 권을 놓을 수 있다면 어떨까요?
한 곳에 여러 정보를 저장할 수 있어서 전체 구조가 더 납작해집니다.
2. 디스크 접근 횟수 줄어듦
B-tree는 디스크 기반 시스템에 적합하게 설계되었습니다. 한 번에 여러 데이터를 저장할 수 있는 노드 구조로 디스크를 읽는 횟수가 줄어듭니다.
예를 들어, 100만 개의 데이터 중 하나를 찾을 때:
이진 트리는 최대 20번 디스크를 읽어야 합니다.
B-tree는 최대 3번만 읽으면 됩니다.
컴퓨터가 하드디스크에서 정보를 읽어오는 건 마치 우리가 책을 꺼내 읽는 것과 같습니다. B-tree는 한 번에 여러 정보를 읽을 수 있어서 책을 꺼내는 횟수가 줄어듭니다. 이렇게 하면 컴퓨터가 덜 힘들어하고 더 빨리 일할 수 있습니다.
3. 캐시 활용에 유리
B-tree는 한 노드에 여러 데이터를 저장하므로, 한 번에 많은 데이터를 메모리로 가져올 수 있습니다. 이렇게 하면 메모리에서 데이터를 빠르게 처리할 수 있어 성능이 좋아집니다.
우리가 공부할 때 한 번에 여러 내용을 외우면 좋은 것처럼, B-tree도 한 번에 여러 정보를 기억합니다. 이렇게 하면 컴퓨터가 정보를 더 빨리 처리할 수 있습니다.
4. 범위 검색에 적합
B-tree는 데이터를 항상 정렬된 상태로 유지하기 때문에, 예를 들어 특정 범위 내의 데이터를 찾을 때 매우 빠르게 처리할 수 있습니다.
예를 들어, 월급이 50,000에서 70,000 사이인 직원들을 찾는 쿼리를 빠르게 실행할 수 있습니다.
도서관에서 책을 찾을 때 번호순으로 정리되어 있으면 쉽게 찾을 수 있습니다. B-tree이와 같이 정보를 순서대로 정리해두기 때문에 특정 범위의 정보를 찾을 때 아주 빠릅니다.
5. 균형 유지 비용이 적다
이진 트리(특히 AVL 트리나 레드-블랙 트리)는 삽입이나 삭제를 할 때 트리의 균형을 맞추기 위해 많은 작업이 필요하지만, B-tree는 균형을 유지하는 데 더 적은 비용이 듭니다. 노드가 나뉘거나 합쳐지는 일이 자주 발생하지 않기 때문입니다.
새 책을 꽂거나 책을 빼도 책장이 쉽게 엉망이 되지 않는 것처럼, B-tree도 정보를 추가하거나 삭제할 때 전체 구조를 크게 바꾸지 않아도 됩니다.
6. 공간을 더 효율적으로 사용
B-tree는 한 노드에 여러 개의 키를 저장할 수 있어서, 트리 전체를 관리하는 데 필요한 추가 공간(포인터 등)이 줄어듭니다. 이로 인해 저장 공간을 더 효율적으로 사용할 수 있습니다.
7. 삽입/삭제 성능
B-tree는 많은 데이터를 삽입하거나 삭제할 때도 성능이 크게 떨어지지 않습니다. 노드가 분할되거나 병합되더라도 트리 전체 구조를 크게 변경하지 않기 때문입니다.
8. 동시 작업에 유리
B-tree는 데이터베이스에서 여러 사용자가 동시에 작업할 때도 효율적입니다. 한 번에 큰 단위의 노드를 처리할 수 있기 때문에, 여러 사용자가 데이터를 처리할 때 충돌이 적게 일어납니다.

B-Tree 설명

인덱스 동작방식 예제

아래의 표처럼 일반의 Member데이터가 쌓여있다고 가정합니다.
옆에 표를 인덱스로 생성하게 되면 아래와 같은 표가 생성됩니다.
Member
B-tree based Index
a
b
c
2
7
1
2
9
7
13
5
7
2
a
ptr
1
2
2
3
5
7
7
7
9
13
B-tree based Index를 보면 우측에 Pointer란 값이 존재하며, 이 값을 통해서 Member의 튜플의 값을 참조 할 수 있게 됩니다.
1.
select * from Member where a = 9;를 실행시키게 되면, B-tree Based Index를 바이너리 서치를 통해서 찾게 됩니다.
2.
B-tree구조에서 바이너리 서치를 통해서 일치하는 a의 값을 찾으면 ptr을 통해서 원본 데이터의 값을 추출합니다.

그렇다면 개발자는 무엇을 잘 해야 되는가?

1.
인덱스의 동작 방식을 알아야 됩니다.
a.
추후 DB 옵티마이저를 튜닝해야 될 때 각각의 장담점을 알고 있으면 적재적소에 상용할 수 있을 것입니다.
B-tree 인덱스
Hash 인덱스
Bitmap 인덱스
복합 인덱스
클러스터드 인덱스
커버링 인덱스
2.
인덱스를 어떻게 주면 효율적으로 최대한 자원의 낭비 없이 사용할 수 있을지 알아야 됩니다.
B-Tree 인덱스는 table을 write (insert, update, delete)할 때마다 index를 계속 수정해 줘야 합니다. 때문에 wirte를 할때마다 오버헤드가 발생합니다.
index마다 각각 저장 공간을 차지하기 때문에 추가적인 저장 공간이 사용됩니다.
그렇다면 인덱스를 선언할 때 어떻게 선언해야지 자원의 낭비가 최대한 없을 수 있을까?
id
name
code
backnumber
1
콜라
0001
0001-1
2
사이다
0002
0001-2
3
환타
0003
0001-3
조회 쿼리가
select * from item where id =? select * from item where name =? select * from item where code = ? and backnumber =? select * from item where code =?
SQL
복사
위와 같이 4개의 조회 쿼리가 존재한다면 우리는 3개의 index를 지정해 줄 수 있습니다.
id: 기본 키(primary key)로 사용되는 경우 자동으로 인덱스가 생성됩니다.
name : 단일 인덱스를 추가합니다.
codename : 복합 인덱스로 추가합니다
그렇다면? code 단일 index가 또 필요할까? 현재 위 4개의 컬럼에 굳이 인덱스를 전부 넣어줄 필요가 없을 것입니다. 이유는 복합 인덱스 첫 시작이 code로 시작이 되고 있으므로 (code)단일 인덱스 대신에 사용하면 되기 때문입니다.
제가 실무에서 가장 많이 만나본 예제입니다. where 조건에 있다면 무조건 인덱스를 단건 씩 추가하는 경우를 많이 접해보았고, 이러한 구조에 대해 알지 못하면 자원의 낭비가 심할 것입니다.
때문에 복합 인덱스를 사용할 때 최대한 많이 사용되는 컬럼을 앞에 배치해두고 같이 사용하는 방법으로 단일 인덱스의 자원의 낭비를 줄일 수 있다는것을 인지하는 게 중요하다고 생각합니다.
정리하자면
인덱스를 무조건 많이 만든다고 성능이 좋아지는 것이 아닙니다. 적절한 설계가 중요하며, 중복된 인덱스는 오히려 성능을 저하시킬 수 있습니다.
인덱스 설계 시, 쿼리에서 자주 사용되는 컬럼을 기준으로 복합 인덱스를 생성하고, 불필요한 단일 인덱스를 지양하는 것이 자원 낭비를 막는 최적의 방법입니다.
오늘은 B-tree와 인덱스에 대해 설명하였습니다. 실무에서 가장 많이 보았던 단일인덱스선언과 복합 인덱스 선언에 대해 작성하게 되었고, 저 또한 이러한 특성을 알지 못하고 작성했던 경험이 있어 작성하게 되었습니다.
감사합니다.