서적/Real MySQL

08. 인덱스 [8.1 디스크 읽기 방식 ~ 8.4 R-Tree 인덱스]

Mo_bi!e 2025. 10. 14. 21:40
08장 인덱스: 8.1 디스크 읽기 방식 ~ 8.4 R-Tree 인덱스

 

8.1 디스크 읽기 방식 (Disk Reading Methods)
인덱스가 데이터베이스 성능에 미치는 영향을 이해하려면, 데이터를 저장하는 디스크의 작동 방식, 특히 I/O (Input/Output) 성능을 먼저 이해가 필요합니다.
8.1.1 하드 디스크 드라이브(HDD)와 솔리드 스테이트 드라이브(SSD)
HDD와 SSD는 물리적 작동 방식이 다릅니다. 전통적인 HDD는 데이터를 읽기 위해 디스크를 회전시키고 헤드를 움직여야 하므로(기계적 작동), 데이터를 찾는 데 걸리는 시간인 탐색 시간(Seek Time)이 I/O 성능에 큰 영향을 미칩니다. 반면 SSD는 플래시 메모리를 사용하므로 기계적 지연이 없어 I/O 작업이 훨씬 빠릅니다.
8.1.2 랜덤 I/O와 순차 I/O
이 섹션은 인덱스의 성능 원리를 설명하는 가장 중요한 기초 개념입니다.
 순차 I/O (Sequential I/O): 물리적으로 연속된 위치에 저장된 데이터를 연속적으로 읽어 들이는 방식입니다. 대량의 데이터를 읽을 때 효율적이며, HDD와 SSD 모두에서 빠른 성능을 보장합니다.
 랜덤 I/O (Random I/O): 디스크의 여러 위치에 분산된 데이터 블록을 읽기 위해 헤드를 끊임없이 이동시키는 방식입니다.
 랜덤 I/O의 문제점: HDD 환경에서는 랜덤 I/O가 발생할 때마다 헤드 이동에 드는 시간(Seek Time) 때문에 성능 저하가 극심합니다.
 인덱스의 역할: 인덱스는 본질적으로 대량의 순차 I/O를 회피하고, 필요한 데이터만 소량의 랜덤 I/O로 접근하도록 도와, 데이터 검색 시간을 획기적으로 줄이는 역할을 수행합니다.
【실무상 중요성】
HDD 기반 시스템에서는 랜덤 I/O의 최소화가 성능 튜닝의 절대적인 목표였습니다. 인덱스를 잘못 사용하거나 생성하지 않아 풀 테이블 스캔(Full Table Scan)이 발생하면 순차 I/O가 발생하지만, 인덱스를 통해 필요한 레코드를 찾을 때 발생하는 I/O는 대부분 랜덤 I/O입니다. 따라서 인덱스를 사용하는 목적은 전체 테이블 순차 I/O보다 적은 횟수의 랜덤 I/O로 처리하여 성능을 개선하는 데 있습니다.
하지만 SSD 환경이 보편화되면서 랜덤 I/O의 성능 지연이 HDD에 비해 크게 감소했습니다. 이로 인해 인덱스 설계의 중요성이 줄어든 것은 아니지만, 인덱스가 예상대로 작동하지 않더라도 과거 HDD 환경처럼 치명적인 성능 저하가 발생하지 않을 수 있습니다.
 
 
8.2 인덱스란? (What is an Index?)
인덱스는 데이터를 빠르게 찾거나 정렬 작업을 효율적으로 수행할 수 있도록 돕는 데이터 구조입니다. 인덱스를 사용하면 전체 테이블 데이터를 스캔하지 않고도 필요한 레코드에 빠르게 접근할 수 있습니다.
 
8.3 B-Tree 인덱스 (B-Tree Index)
B-Tree 인덱스는 MySQL에서 가장 보편적이고 핵심적인 인덱스 구조입니다. 대부분의 DBMS에서 사용되는 일반적인 인덱스 알고리즘입니다.
8.3.1 구조 및 특성
B-Tree는 균형 잡힌 트리(Balanced Tree) 구조를 특징으로 합니다. 이 구조 덕분에 테이블의 레코드 수가 수백만 건에 달하더라도, 인덱스의 깊이(Depth)가 3~4단계 정도로 유지되어 원하는 데이터를 찾기 위한 디스크 I/O 횟수가 매우 적게 유지됩니다.
1. 리프 노드(Leaf Node)의 연결: B-Tree의 가장 하위에 있는 리프 노드들은 좌우로 연결 리스트 형태로 연결되어 있습니다. 이 덕분에 특정 키를 검색한 후, 인덱스를 사용하여 키를 순차적으로 읽어 나가는 작업(Index Range Scan)이 효율적으로 가능해집니다.
2. 데이터 저장: 인덱스 키는 항상 정렬된 상태를 유지하며, 실제 데이터 레코드의 주소(세컨더리 인덱스의 경우)나 데이터 레코드 자체(클러스터링 인덱스의 경우)를 포함합니다.
8.3.2 B-Tree 인덱스 키 추가 및 삭제
B-Tree 인덱스는 데이터를 효율적으로 관리하기 위해 삽입 및 삭제 시 특정한 연산을 수행하여 균형을 유지합니다.
 키 추가 (Insertion): 새로운 키가 삽입될 공간이 없을 경우, 해당 노드는 두 개의 노드로 쪼개지는 노드 분할(Split) 작업을 수행합니다. 이는 B-Tree가 항상 균형을 유지하게 하는 핵심 원리입니다.
 키 삭제 (Deletion): 키가 삭제되면, 해당 노드의 데이터가 너무 적을 경우 인접 노드와 합쳐지는 노드 병합(Merge) 작업을 수행할 수도 있습니다.
8.3.3 B-Tree 인덱스 사용에 영향을 미치는 요소
쿼리 최적화기(Optimizer)가 B-Tree 인덱스를 사용할지 여부를 결정하고, 사용 시 효율성을 극대화하는 실무적 고려 사항들입니다:
1. 왼쪽 값 기준 매칭 (Leftmost Prefix Rule): B-Tree 인덱스는 키의 가장 왼쪽 부분부터 순서대로 조건을 비교하고 검색할 수 있도록 설계되었습니다 (8.3.5 다중 칼럼 인덱스, 8.3.6 정렬 및 스캔 방향 섹션과 관련됨). 예컨데 (A, B, C) 컬럼으로 구성된 복합 인덱스가 있다면, A 또는 (A, B) 또는 (A, B, C) 조건으로 검색해야 인덱스를 효율적으로 사용할 수 있습니다.
2. 클러스터링 인덱스와 세컨더리 인덱스의 차이: InnoDB 엔진에서 프라이머리 키는 클러스터링 인덱스로, 데이터가 물리적으로 인덱스 순서에 맞게 저장됩니다 (4.2.1 프라이머리 키에 의한 클러스터링과 관련됨). 반면 세컨더리 인덱스는 인덱스 키와 함께 프라이머리 키 값을 저장하며, 실제 데이터 레코드를 읽기 위해 프라이머리 키를 이용해 데이터 페이지를 다시 찾아가는 과정(랜덤 I/O)이 필요할 수 있습니다.
3. 범위 검색 및 정렬: B-Tree는 범위 검색(BETWEEN, >, <) 및 순차적인 데이터 정렬(ORDER BY)에 매우 효율적입니다 (8.3.6 정렬 및 스캔 방향과 관련됨).
【B-Tree 실무적 관점】
 인덱스 설계의 핵심: 쿼리의 WHERE 절이나 ORDER BY 절에서 자주 사용되는 컬럼을 B-Tree 인덱스의 선두 컬럼으로 배치해야 합니다.
 복합 인덱스 순서: 여러 컬럼을 묶어 인덱스(복합 인덱스)를 만들 때는, 사용 빈도나 검색 효율성을 고려하여 순서를 결정해야 합니다. 가장 왼쪽의 컬럼이 검색 조건에 사용되지 않으면 나머지 컬럼들은 인덱스의 혜택을 받기 어렵습니다.
 성능 최적화: B-Tree 인덱스를 통해 데이터에 접근할 때 데이터 페이지를 디스크에서 메모리로 읽어 오는 횟수(I/O)를 최소화하는 것이 인덱스 튜닝의 목표입니다.

 

 

8.4 R-Tree 인덱스 (R-Tree Index)
R-Tree 인덱스는 B-Tree와 달리 공간 데이터(Spatial Data)를 처리하기 위해 특수하게 설계된 인덱스 구조입니다.
8.4.1 구조 및 특성
R-Tree는 주로 2차원 또는 다차원 데이터를 효율적으로 저장하고 검색할 수 있도록 고안되었습니다.
 MBR (Minimum Bounding Rectangle): R-Tree는 공간 객체들(점, 선, 다각형)을 포함하는 최소 경계 사각형(MBR)을 생성하고, 이 MBR들을 트리 구조로 계층화하여 구성합니다.
 효율성: R-Tree 인덱스를 사용하면 특정 영역 내에 포함되거나 교차하는 공간 객체를 찾는 쿼리(Spatial Query)를 일반 B-Tree보다 훨씬 빠르게 처리할 수 있습니다.
8.4.2 R-Tree 인덱스의 용도
MySQL에서는 POINT, LINESTRING, POLYGON과 같은 공간 데이터 타입에 대해 R-Tree 인덱스를 생성하여 사용합니다. 이는 지리 정보 시스템(GIS)이나 위치 기반 서비스(LBS)와 같이 공간 검색이 중요한 응용 프로그램에 필수적입니다.
【R-Tree 실무적 관점】
 R-Tree는 일반적인 숫자나 문자열 검색에는 적합하지 않으며, 오직 공간 데이터 검색을 위해 사용해야 합니다.
 MySQL 서버에 공간 데이터 쿼리(예: "현재 위치 반경 5km 이내의 모든 식당 찾기")가 발생한다면, 해당 공간 데이터 컬럼에 R-Tree 인덱스가 정확하게 적용되었는지 반드시 확인해야 합니다.