인덱스는 데이터를 좀 더 빨리 찾을 수 있도록 도와주는 도구이다.
찾아보기가 있는 책은 찾아보기에 주요 용어가 가나다순, 알파벳순으로 정렬되어 있고 용어 옆에 쪽수가 적혀 있어 해당 페이지를 펼치면 원하는 내용을 바로 찾을 수 있다. MySQL의 인덱스는 바로 이와 같은 찾아보기와 상당히 비슷한 개념이다.
책이 거의 모든 페이지에 나오는 단어를 찾아보기에 모두 표시하면 찾아보기의 분량이 엄청나게 많아져서 본문보다 두꺼워지는 것처럼 필요 없는 인덱스를 만들면 데이터베이스가 차지하는 공간만 늘어나고, 인덱스를 이용하여 데이터를 찾는 것이 전체 테이블을 찾아 보는 것보다 훨씬 느려진다.
장점
장점
MySQL에서 사용하는 인덱스에는 클러스터형 인덱스(clustered index)와 보조 인덱스(secondary index)가 있다.
클러스터형 인덱스
보조형 인덱스
(참고)
SHOW INDEX FROM 테이블명 을 통해 테이블 생성 시 제약 조건으로 자동 새성된 인덱스를 확인할 수 있다. SELECT * FROM 테이블명 수행 시 PK로 인해 생성된 클러스터형 인덱스를 통해 자동 정렬된 결과가 나온다. 자료 구조에 나오는, 범용적으로 사용되는 데이터 구조로 균형이 잡힌 트리이다.
트리 구조에서 데이터가 존재하는 공간을 노드라고 한다.
MySQL에서는 노드를 페이지라고 한다. 페이지에는 최소한의 저장 단위로 크기가 16KB이며, 아무리 작은 데이터를 저장하더라도 1개의 페이지(16KB)를 사용한다.
B-Tree의 데이터 삽입
[예제]
ㅤ
다음 쿼리문을 사용해 인덱스 없이 테이블을 생성하고 데이터를 조회하면 정렬되지 않은 것을 확인할 수 있다.
CREATE DATABASE IF NOT EXISTS testDB;
USE testDB;
DROP TABLE IF EXISTS clusterTBL;
CREATE TABLE clusterTBL (
userID CHAR(8),
userName VARCHAR(10)
);
INSERT INTO clusterTBL (userID, userName) VALUES
('YJS', '유재석'),
('KHD', '강호동'),
('KKJ', '김국진'),
('KYM', '김용만'),
('KJD', '김제동'),
('NHS', '남희석'),
('SDY', '신동엽'),
('LHJ', '이휘재'),
('LKK', '이경규'),
('PSH', '박수홍');
SELECT * FROM clusterTBL;
userID에 클러스터형 인덱스를 구성하고 다시 데이터를 다음과 같다.
이는 다음과 같이 클러스터형 인덱스가 내부 구조를 가지기 때문이다.

userID 열에 UNIQE 제약 조건을 설정하여 보조 인덱스를 만들고 데이터를 확인하면 다음과 같다.
CREATE DATABASE IF NOT EXISTS testDB;
USE testDB;
DROP TABLE IF EXISTS secondaryTBL;
CREATE TABLE secondaryTBL (
userID CHAR(8),
userName VARCHAR(10)
);
INSERT INTO secondaryTBL (userID, userName) VALUES
('YJS', '유재석'),
('KHD', '강호동'),
('KKJ', '김국진'),
('KYM', '김용만'),
('KJD', '김제동'),
('NHS', '남희석'),
('SDY', '신동엽'),
('LHJ', '이휘재'),
('LKK', '이경규'),
('PSH', '박수홍');
ALTER TABLE secondaryTBL ADD CONSTRAINT UK_secondary_TBL_userID UNIQUE (userID);
SELECT * FROM secondaryTBL;
보조 인덱스는 다음과 같이 내부적으로 저장된다.
클러스터형 인덱스는 데이터 검색 속도가 보조 인덱스보다 빠르다.
예: NHS를 검색하는 경우, 클러스터형 인덱스에서는 루트 페이지와 리프 페이지 총 2개의 페이지만 읽지만 보조 인덱스에서는 인덱스 페이지의 루트 페이지, 리프 페이지, 데이터 페이지 총 3개의 페이지를 읽어야 한다.
![]() |
![]() |
보조 인덱스의 성능 부하가 클러스터형 인덱스보다 적다. 하지만 전체적인 성능 부하는 보조 인덱스가 클러스터형 인덱스보다 많다.
![]() |
![]() |
클러스터형 인덱스의 특징
보조 인덱스의 특징
인덱스 생성 형식
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name
[index_type]
ON TBL_userName (index_col_userName, )
[index_option]
[algorithm_option | lock_option]
index_col_userName:
col_userName [(length)] [ASC | DESC]
index_type:
USING {BTREE | HASH}
index_option:
KEY_BLOCK_SIZE [=] value
| index_type
| WITH PARSER parser_userName
| COMMENT 'string'
algorithm_option:
ALGORITHM [=] {DEFAULT | INPLACE | COPY}
lock_option:
LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
CREATE INDEX문으로 인덱스를 만들면 보조 인덱스가 생성된다.CREATE INDEX문으로는 클러스터형 인덱스를 만들 수 없으며, 클러스터형 인덱스를 만들려면 앞에서 배운 ALTER TABLE 문을 사용해야 한다. CREATE INDEX문의 UNIQUE 옵션은 고유한 인덱스를 만들 때 사용한다. index_type은 생략 가능하며, 생략할 경우 기본 값인 B-Tree 형식이 사용된다. 인덱스 삭제 형식
DROP INDEX index_name ON TBL_userName
[algorithm_option | lock_option]
algorithm_option:
ALGORITHM [=] {DEFAULT | INPLACE | COPY}
lock_option:
LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
DROP INDEX 인덱스이름 ON 테이블이름;
PRIMARY를 넣는다. 다음과 같은 테이블이 있다.
CREATE DATABASE IF NOT EXISTS testDB;
USE testDB;
DROP TABLE IF EXISTS yeongu;
CREATE TABLE yeongu (
userID CHAR(8) PRIMARY KEY,
userName VARCHAR(10),
birthYear INT,
addr CHAR(8)
);
INSERT INTO yeongu (userID, userName, birthYear, addr) VALUES
('SYW', '서영우', 2003, '광주'),
('KDY', '김다영', 2003, '여수'),
('KKY', '김가연', 2001, '광주'),
('JBG', '조배경', 2001, '익산'),
('JSI', '정수인', 2001, '광주'),
('KMD', '강명덕', 2001, '제주'),
('SMB', '심민보', 2000, '광주'),
('KJM', '김종민', 2001, '광주'),
('BGH', '백경환', 2000, '여수');
SELECT * FROM yeongu;
어떤 인덱스가 생성되어 있는지 확인해보자.
SHOW INDEX FROM yeongu;

주소(addr) 열에 단순 보조 인덱스를 생성해보자. 다음처럼 생성된 보조 인덱스를 확인할 수 있다. Non_unique도 1로 표시됐다.
CREATE INDEX yeongu_addr ON yeongu (addr);

출생 연도(birthYear) 열에 고유 보조 인덱스를 생성해보자. 중복값이 있어 에러가 발생하고 생성되지 못하였다.
CREATE UNIQUE INDEX yeongu_birthYear ON yeongu (birthYear);

이름(userName) 열에 고유 보조 인덱스를 생성하면 문제없이 생성된다. 이름(userName) 열과 출생 연도(birthYear) 열을 조합하여 인덱스를 생성할 수도 있다.
CREATE UNIQUE INDEX yeongu_userName ON yeongu (userName);
CREATE INDEX yeongu_userName_birthYear ON yeongu (userName, birthYear);
DROP INDEX yeongu_userName ON yeongu;

SELECT * FROM yeongu WHERE userName = '서영우' and birthYear = 2003;
다음은 두 열이 조합된 조건문의 쿼리에 인덱스가 사용된 결과이다.

동일한 데이터를 구성한 테이블에서 인덱스를 사용하지 않았을 때 쿼리 결과이다. 쿼리 속도가 차이 나는 것을 확인할 수 있다.

인덱스 삽입은 어엄청 많은 데이터로 실험해야 하니까 pass..
이제 인덱스를 삭제해보자. 순서에 맞게 삭제해주는 것이 중요하다. 보조 인덱스를 먼저 삭제하고 이후에 자동으로 생성된 클러스터형 인덱스를 삭제한다.
DROP INDEX yeongu_addr ON yeongu;
DROP INDEX yeongu_userName_birthYear ON yeongu;
ALTER TABLE yeongu DROP PRIMARY KEY;