MySQL

인덱스

iksadnorth 2023. 8. 2. 17:32

해당 게시물은 'Real MySQL 8.0'라는 책을 참고해서 작성했습니다.

👣 랜덤 I/O와 순차 I/O

랜점 I/O라는 것은 물리적으로 인접하지 않은 메모리의 내용을 조회하는 행위를 말하는 것이고
순차 I/O는 물리적으로 인접한 메모리의 내용을 조회하는 행위다.

HDD 같은 경우엔, 디스크 헤더를 움직여서 메모리를 조회하기 때문에 두 방식의 차이는 매우 크다.
만약 N개의 랜덤 I/O를 요구한다면 N번의 SystemCall을 해야 하고
순차 I/O의 경우엔 1번의 SystemCall만 요구하기 때문에
N배 더 빠르다고 볼 수 있고 이것은 매우 큰 차이다.

SDD도 마찬가지로 두 방식에서 차이가 크기 때문에
SSD 드라이브 사양에도 항상 순차 I/O, 랜덤 I/O의 성능을 명시하도록 되어 있다.

결론적으로 빠른 조회를 위해 순차 I/O를 더 적극적으로 활용해야 한다.

👣 인덱스

인덱스에서는 자료를 쉽게 찾기 위해 자료들을 정렬한 상태로 유지한다.
여러 알고리즘으로 정렬할 수 있지만 그중 자주 사용되는 것은 B-Tree와 Hash Table이다.

👣 B-Tree 인덱스

B-Tree 인덱스의 경우, Hash Table과 달리 범위 검색과 정렬이 가능하기에 자주 사용되는 알고리즘이다.
B-Tree는 트리의 일종으로 스스로 균형적인 상태로 정렬하는 특징을 가지고 있다.

 

B-tree

B-tree 역시 'AVL 트리'와 '레드 블랙 트리'와 같이 Balanced Tree이다. 다만 균형 이진 탐색 트리는 아니다. B-tree는 앞서 살펴봤던 트리들과는 달리 Node당 1 개 이상의 데이터가 포함된다. Node 안은 여러

ikadnorth.tistory.com

👣 B-Tree 인덱스 데이터 읽기

👣 인덱스 레인지 스캔

검색해야할 인덱스의 범위가 결정됐을 때 사용하는 방식이다.
예시로 다음 쿼리에서 '인덱스 레이지 스캔'이 사용된다.

SELECT * FROM employees WHERE first_name BETWEEN 'Ebbe' AND 'Gad';

해당 스캔은 다음과 같이 탐색한다.

1. 우선 인덱스를 활용해 스캔 시작 위치를 검색한다.
2. 해당 지점부터 필요한 방향(오름차순, 내림차순)으로 순차적으로 읽어 나간다.
3. 2번에서 읽어 들인 인덱스 키와 레코드 주소를 활요해 실제 레코드 위치로 가서 정보를 가져온다.

👣 인덱스 풀 스캔

인덱스 선두 컬럼이 조건절에 없으면 인덱스 풀 스캔을 사용한다.
무슨 소리냐면, 예를 들어 인덱스가 (칼럼 A, 칼럼 B, 칼럼 C)로 구성되어 있을 때,

SELECT * FROM employees WHERE B = '1' AND C = '2';

위와 같이 A칼럼을 사용하지 않는 경우를 일컫는다.

해당 경우, 인덱스를 활용하긴 어렵지만 조건절이 인덱스만으로도 처리가 가능하기 때문에
굳이 테이블 풀 스캔을 고려할 이유가 없어서 인덱스 풀 스캔을 사용하게 된다.

👣 루스 인덱스 스캔

루스 인덱스 스캔이란 느슨하게 또는 듬성듬성하게 인덱스를 읽는 것을 의미한다. 
루스 인덱스 스캔 인덱스 레인지 스캔과 비슷하게 동작하지만
중간마다 필요하지 않은 키값은 무시하고 다음으로 넘어가는 형태로 처리한다.
일반적으로 
group by 또는 max 등의 함수에 대해 최적화를 하는 경우에 사용된다.

SELECT dept_no, MIN(emp_no) FROM dept_emp
WHERE dep_no BETWEEN 'd002' AND 'd004'
GROUP BY dept_no;

👣 B-Tree 인덱스 데이터 정렬

👣 인덱스 정렬

실제로 인덱스를 정렬할 때,
오름차순, 내림차순을 구분해서 저장하는 것이 아니라
우선 오름차순으로 정렬하고 읽을 때, 오름차순은 정방향으로 내림차순은 역방향으로 읽을 뿐이다.

다만 MySQL 8.0 버전부터는 다음과 같은 형태의 정렬 순서를 혼합한 인덱스도 생성할 수 있게 되었다.

CREATE INDEX ix_teamname_username ON employees (team_name ASC, user_score DESC);

👣 R-Tree 인덱스

R-Tree(Rectangle-Tree)는 다른 말로 공간 인덱스라고도 불리우며
주로 경도, 위도, 좌표 위치, 등등을 정렬하기 위해 사용되는 인덱스 입니다.

 R-tree는 2D 또는 3D 공간 데이터에 대한 인덱스를 생성하는데 주로 사용됩니다.
이러한 인덱스를 통해 공간 데이터를 빠르게 검색하고 관리할 수 있습니다.

예를 들어, "현재 위치에서 200km 이내의 모든 레스토랑을 찾아라"
와 같은 질의에 대해 빠르게 답을 도출할 수 있다.

R-tree는 이름 그대로 최소 경계 사각형(Minimum Bounding Rectangle)으로 공간을 분리하는데,
MBR 끼리 겹칠 수도 있고 상위 레벨 MBR은 하위 레벨 MBR을 포함하는 트리 구조를 이룬다.

👣 전문 검색 인덱스

해당 인덱스는 문서 내용 전체를 인덱스화해서
특정 키워드가 포함된 문서를 검색하는 것과 같은 연산을 수행할 때,
사용하는 인덱스다.

👣 어근 분석 알고리즘

2 단계로 색인 작업이 수행된다.

1. 불용어 처리
검색에 가치없는 단어[~에, ~가, 에구구 등등]을 제거하는 작업

2. 어근 분석
검색어로 선정된 단어의 원형['빨간색'의 빨~ 등등]을 찾는 작업이다. 

👣 n-gram 알고리즘

'어근 분석 알고리즘'은 만족할 만한 결과를 내기 위해 많은 노력과 시간이 필요하다.
때문에 전문적인 검색 엔진을 고려하는 게 아니라면 사용하는 알고리즘이 n-gram 알고리즘이다.

정말 단순하게 글자를 단어 기준으로[공백으로 구분하는 기준] n개의 단어를 인덱스로 삼는 것이다.
예를 들어, 다음 문장을 2-gram으로 토큰 추출을 하면, 다음과 같다.

apple is red
ap, pp, pl, le, is, re, ed

위 방식으로 인덱스를 생성한 다음, 불용어를 제거해 유용한 키워드만 남겨 놓는다.

👣 함수 기반 인덱스

실제로 존재하는 칼럼을 가지고 인덱스를 만드는 것이 아닌 연산 결과를 인덱스값으로 설정하는 방법이 제공된다.
예를 들어, '성' 칼럼과 '이름' 칼럼이 따로 존재해 운영되지만 검색에서만 '성과 이름'을 사용할 뿐 데이터를 성과 이름을 구분해서 저장하고 싶다면 다음과 같이 인덱스를 부여할 수 있다.

CREATE TABLE user (
    first_name VARCHAR(10),
    last_name VARCHAR(10),
    
    INDEX ix_fullname ( (CONCAT(first_name, last_name)) )
)

👣 클러스터링 인덱스

테이블의 Primary Key에 대해서만 적용되는 내용이다.
해당 인덱스는 InnoDB 스토리지 엔진에만 존재하는 인덱스다.

유의할 점은 PK 조건이 부여된 칼럼으로 검색하는 것은 매우매우 큰 이점을 가져다주기 때문에 
PK 를 신중히 선택해야 한다. 성능 차이가 유의미하게 난다.

 

인덱스

👣 개요 인덱스는 보통 B-트리로 구성되어 특정 값에 대한 조회가 O(log n) 복잡도로 수행된다. 만약 인덱스가 존재하지 않는 칼럼을 이용해서 조회를 하면 O(n) 복잡도로 , 즉 선형 탐색으로 검색

ikadnorth.tistory.com

👣 유니크 인덱스

단순히 Unique 제약 조건이 붙은 인덱스를 의미한다.
Unique 인덱스는 인덱스의 키 값을 Write할 때,
중복된 값이 있는지 없는지 체크하는 과정이 한 단계 더 필요하다.
때문에 꼭 필요한 상황이 아니라면 붙일 이유가 없다.

 

👣 외래키

외래키는 InnoDB에서만 사용 가능하다.
외래키 제약이 생성되면 자동으로 연관된 테이블의 칼럼에 인덱스가 생성된다.

외래키 제약이 존재하면
외래키 제약이 존재하는 부모 레코드을 변경하는 트랜잭션을 가지고 있으면
연관된 자식 레코드도 잠금이 생긴다. 그 반대도 마찬가지다.

다만, 외래키와 연관되지 않은 칼럼의 변경은 잠금을 전이시키지 않는다.

'MySQL' 카테고리의 다른 글

옵티마이저, 힌트  (0) 2023.09.13
트랜잭션과 잠금  (0) 2023.08.02
MySQL 로그 파일  (0) 2023.08.01
MyISAM 스토리지 엔진  (0) 2023.08.01
InnoDB 스토리지 엔진  (0) 2023.08.01