DB Index

EBAB!·2023년 9월 16일
0

Algorithm & DA

목록 보기
8/12

Index

많은 사람들이 데이터베이스 인덱스의 개념을 설명할 때 책의 맨 마지막에 있는 색인(찾아보기)에 비유합니다.
예를 들어서 여러분이 깔끔한 파이썬 탄탄한 백엔드 책을 보고 있다고 가정해 봅시다. 만약에 “트렌젝션”이라는 단어가 책 어디에 나왔는지 찾아야하는 상황이라고 해봅시다.

책의 인덱스

책에 색인(찾아보기)이 없는 경우라면, 책을 첫 페이지에서부터 한장씩 남겨가며 “트렌젝션” 단어를 찾는 수밖에 없습니다. 운이 좋아서 찾는 내용이 책의 앞부분에서 “트렌젝션” 단어를 찾았다고 하더라도 책 전체에서 ‘트렌젝션'이라는 단어가 한 번만 나온다는 보장이 없으므로, 책의 마지막 장까지 계속해서 찾아봐야 합니다.

이번에는 책에 색인(찾아보기)이 있는 경우를 살펴보겠습니다. 색인(찾아보기)은 “ㄱ”, “ㄴ”, “ㄷ”, …과 같은 순서로 이미 정렬되어 있어서 “ㅌ” 부분을 찾아보면 그 중에서 쉽게 “트렌젝션" 단어를 찾을 수 있을 것입니다. 그리고 단어 옆에 적혀있는 페이지 번호로 책 내용중에 “트렌젝션" 단어가 있는 위치로 바로 찾아 들어갈 수 있습니다.

또한 색인(찾아보기)의 경우에는 하나의 단어가 몇 개의 페이지에 있다고 하더라도 그 몇 개 페이지가 모두 색인(찾아보기)에 표시되기 때문에 책 전체를 계속해서 찾을 필요가 없이 몇 번만 책을 펼치면 모든 내용을 찾을 수 있습니다.

데이터베이스의 인덱스

데이터베이스의 인덱스 개념은 책의 색인(찾아보기)과 상당히 비슷한 개념입니다. 책의 마지막에 있는 색인(찾아보기)이 데이터베이스의 인덱스에 비유된다면 책의 전체 내용은 데이터 파일에 해당한다고 볼 수 있습니다. 책의 색인을 통해서 알아낼 수 있는 페이지 번호는 데이터 파일에 저장된 레코드(2차원 테이블의 행 데이터)의 주소에 비유될 수 있습니다.

책의 색인(찾아보기)는 책의 분량에 따라서 필요할 수도 있고 필요 없을 수도 있습니다. 10 페이지 이내 분량의 책이라면 색인이 없다고 하더라도 빠르게 내용을 찾을 수 있을 것입니다. 하지만 수천 페이지로 구성된 두꺼운 책이 있다면, 색인 없이는 원하는 내용을 찾는데 많은 시간을 쏟게될 것입니다.

DBMS도 마찬가지로 데이터의 양이 많아지게 되면 테이블의 모든 데이터를 검색해서 원하는 결과를 가져오려면 시간이 오래 걸립니다. 그래서 열(column) 또는 여러개의 열의 값과 해당 레코드(row)가 저장된 주소를 키와 값의 쌍(key-value)으로 삼아서 인덱스를 만들어두는 것입니다.

결국 인덱스는 데이터를 더 빠르게 찾을 수 있도록 도와주는 도구라고 정리할 수 있습니다.

현대 웹시스템에서 다루어지는 데이터의 양은 굉장히 많아지고 복잡해 졌습니다. 수 많은 데이터를 저장해두고 그 많은 데이터에서 원하는 결과를 찾아내는 상황이 빈번하게 일어납니다. 때문에 개발자는 데이터베이스의 인덱스에 대한 개념을 잘 알고 있어야 조회 성능을 개선할 수 있습니다.

정렬

DBMS는 인덱스를 생성할 때, B-Tree 자료구조에 데이터를 정렬해서 저장합니다. 정렬된 자료구조에 데이터를 저장해 놓으면 효율적인 탐색 알고리즘을 사용하여 데이터를 빠르게 찾을 수 있기 때문입니다.

이러한 인덱스의 정렬 특성 덕분에 빠르게 검색을 할 수 있게 되는데, 장점만 존재하는 것은 아닙니다. 이제부터 인덱스가 정렬된 상태를 유지하는 특성으로 인해서 얻을 수 있는 장점과 단점에 대해서 살펴보고 언제 사용하면 좋은지에 대해서 알아보도록 하겠습니다.

인덱스 사용의 장점과 단점

장점

  • 대부분의 경우에 Index 사용으로 검색 속도를 향상시킬 수 있습니다. 다만 항상 그런 것은 아니고 테이블을 조회하는 애플리케이션의 검색 조건에 따라서도 달라질 수 있습니다.
  • 시스템 전체의 성능이 향상됩니다.

단점

  • 인덱스도 table, view와 같이 객체입니다. 테이블의 열 혹은 열들을 기준으로 인덱스를 생성하게되면 추가적인 Disk 공간을 필요로 합니다.
  • 테이블에 처음 인덱스를 생성할 때, 시간이 많이 소요됩니다. 특히 데이터 저장될 때에는 값을 저장되는 순서 그대로 저장됩니다. 테이블에 데이터가 1억개가 저장되어 있다면, 1억개의 데이터로 인덱스를 생성할 때, 정렬된 상태를 유지하기 위해서 많은 시간을 사용하게 됩니다.
  • 데이터의 추가/변경/삭제 작업(INSERT, UPDATE, DELETE)이 자주 일어날 경우에는 정렬된 인덱스에 새롭게 추가해줘야하는데 이때 오히려 성능이 많이 나빠질 수도 있습니다.

Point

정리하면, 인덱스를 잘 사용하면 검색 속도가 월등히 향상되고, 시스템 성능이 좋아지는 반면에 잘 못 사용하면 오히려 사용하지 않는 것보다 더 나쁜 결과를 초래할 수 있다는 사실을 인지하고 사용하시길 바랍니다.


B-트리

B트리(B-tree)는 자가 균형 이진 트리(Self-balancing tree structure)의 일종으로, 데이터베이스 시스템과 파일 시스템에서 널리 사용되는 데이터 구조입니다. B트리는 효율적인 삽입, 삭제, 검색 연산을 가능하게 하며, 디스크에 저장된 대량의 데이터를 빠르게 읽고 쓸 수 있게 해줍니다.

  1. 다수의 자식 노드: B트리의 각 노드는 두 개 이상의 자식 노드를 가질 수 있습니다. 이는 이진 트리와는 다르게, 하나의 노드가 다수의 키를 가질 수 있습니다.
  2. 정렬된 데이터: B트리는 정렬된 상태로 데이터를 유지합니다. 이로 인해 중위 순회(In-order traversal)를 수행하면 정렬된 데이터를 얻을 수 있습니다.
  3. 자가 균형: 삽입과 삭제가 일어날 때, B트리는 자동으로 균형을 유지합니다. 이는 트리의 높이를 로그 시간 내에 유지하므로, 데이터 검색에 필요한 시간 복잡도도 로그 시간으로 제한됩니다.
  4. 디스크 친화적: B트리는 디스크 기반 저장 시스템을 위해 설계되었기 때문에, 디스크 I/O 작업을 최소화하는 데 효율적입니다. 하나의 노드를 읽거나 쓸 때, 여러 키가 함께 읽히거나 쓰여집니다.
  5. 분할과 병합: 삽입이나 삭제 시에 노드가 너무 많거나 적어지면, 자동으로 노드를 분할하거나 병합하여 균형을 유지합니다.

Clustered Index와 Non-Clustered Index

Clustered Index와 Non-Clustered Index는 데이터베이스에서 인덱싱을 구현하는 두 가지 주요 방법입니다. 두 인덱스 유형 모두 B트리나 그 변형을 기반으로 합니다.

Clustered Index

  1. 데이터 정렬: Clustered Index는 테이블의 레코드 자체를 인덱스 키에 따라 정렬합니다. 즉, 인덱스와 데이터가 하나로 저장됩니다.
  2. 유일성: 하나의 테이블에는 하나의 Clustered Index만 존재할 수 있습니다. 이는 테이블 데이터 자체가 하나의 방식으로만 정렬될 수 있기 때문입니다.
  3. 저장 공간: 추가적인 저장 공간을 별로 사용하지 않습니다. 데이터 자체가 인덱스로 동작하기 때문에, 별도의 인덱스 테이블을 유지할 필요가 없습니다.
  4. 검색 성능: 범위 쿼리(range queries)에 매우 효율적입니다. 인덱스를 따라 데이터가 정렬되어 있기 때문에, 한 번의 디스크 접근으로 여러 연속된 레코드를 읽을 수 있습니다.
  5. 삽입/삭제 오버헤드: 새로운 레코드를 삽입하거나 기존 레코드를 삭제할 때, 데이터의 정렬을 유지하기 위해 추가 작업이 필요할 수 있습니다.

Non-Clustered Index

  1. 데이터 정렬: Non-Clustered Index는 테이블의 레코드와 별도로 인덱스 데이터를 저장합니다. 인덱스는 키 값과 해당 레코드의 위치(주로 Clustered Index 또는 Row ID)를 가리키는 포인터로 구성됩니다.
  2. 유일성: 하나의 테이블에 여러 개의 Non-Clustered Index를 가질 수 있습니다.
  3. 저장 공간: 인덱스 데이터는 별도로 저장되므로 추가적인 디스크 공간이 필요합니다.
  4. 검색 성능: 키를 통한 직접 검색에는 빠르지만, 범위 쿼리에 대해서는 Clustered Index보다 일반적으로 느릴 수 있습니다.
  5. 삽입/삭제 오버헤드: 인덱스만 업데이트하면 되기 때문에, Clustered Index에 비해 삽입과 삭제가 빠를 수 있습니다.

3. Index 생성 및 벤치 마킹

지금까지 인덱스가 어떻게 생성되는지 그리고 생성된 인덱스가 어떻게 사용되는지를 알아봤으니 실제로 인덱스를 생성해보겠습니다. 실습에 필요한 데이터셋은 아래 파일에 준비되어있습니다. (총 690만 rows) 실습과 동일한 MySQL 버전은 8.0.27 입니다.

인덱스를 생성하는 문법은 아래와 같습니다.

CREATE INDEX 인덱스명 ON 테이블명 (컬럼명);

아래 명령어를 입력하면 records_username_idx라는 이름으로 인덱스가 생성됩니다.

CREATE INDEX records_username_idx ON records (username);

데이터가 많아 인덱스를 생성하는데만 13초가 걸린 것을 확인할 수 있습니다.

인덱스 삭제하는 문법은 아래와 같습니다.

DROP INDEX 인덱스명 ON 테이블명;
DROP INDEX records_username_idx ON records;

username 컬럼에 대한 인덱스를 생성했으니 실제로 인덱스를 사용하면 속도가 빨라지는지 테스트해보겠습니다.

username 컬럼 인덱스 없이 실행한 결과

username 컬럼 인덱스를 생성한 뒤 실행한 결과

이렇게 간략히 진행한 테스트에서 약 93배 정도의 속도 차이가 나는 것을 확인할 수 있습니다.

profile
공부!

0개의 댓글