인덱스는 책의 "찾아보기"와 같다
수 만개의 데이터 중 내가 원하는 데이터를 찾는 것은 쉽지 않을 것이다. 이를 위해 "찾아보기" 기능이 데이터베이스의 인덱스
이다
찾아보기
는 언뜻 장점만 있어 보이지만 단점이 있다.
직관적인 비유를 위해 명부에 김
을 찾아본다고 생각해보자
매번 찾아보기
와 본문을 번갈아 보며 김
이 있는 모든 곳을 찾아봐야 하는데 찾아보기
의 양과 번갈아보는 일 모두 비효율적이게 된다.
이게 데이터베이스의 인덱스에도 똑같이 적용된다. 즉, 불필요한 인덱스는 오히려 성능 저하를 일으킨다.
장점
단점
크게 클러스터형 인덱스, 보조 인덱스을 나뉨
클러스터형 인덱스
보조 인덱스
인덱스는 테이블의 열(컬럼) 단위에 생성, 하나의 열에는 하나의 인덱스 생성 가능
SHOW INDEX FROM ~~
으로 확인 가능SHOW INDEX FROM table1;
어느 속성을 기준으로 정렬할래?
클러스터형 인덱스는 기본 키로 지정하면 자동 생성된다.
특정 열을 기본 키로 지정하면 클러스터형 인덱스가 생성되고 그 열을 기준으로 정렬 된다
<기본키 지정 X = 클러스터형 인덱스 생성 X>
<기본키 지정 O = 클러스터형 인덱스 생성 O, mem_id 기준 자동 정렬>
고유키를 지정하면 보조 인덱스가 생성된다.
기본키를 지정하면 자동 생성되는 클러스터형 인덱스와 다르게 보조 인덱스는 여러 개 지정할 수 있고 자동정렬 되지 않는다.
<고유키 설정으로 보조 인덱스 생성>
찾아보기
가 추가된다고 책의 본문이 변경되지 않는 것과 같음인덱스를 위해 다양한 자료구조가 사용되는데 주로 해시 테이블과 B+Tree, B-Tree 구조 등이 많이 사용된다.
MySQL의 데이터베이스 엔진인 InnoDB는 그 중 B-tree를 개선한 B+Tree를 사용한다.
[B-Tree 자료구조]
[페이지?]
쉽게 말하면 B+tree 구조의 노드가 페이지
이다.
즉, 인덱스를 구현하기 위해 사용한 B-tree 구조의 각 노드를 MySQL에서는 페이지
라고 부르는 것이다.
하지만 좀 더 자세히 배우면 디스크와 메모리(버퍼풀)에 데이터를 읽고 쓰는 최소 작업 단위를 페이지
라 부른다.
인덱스, 테이블, PK(클러스터 인덱스) 등은 모두 페이지 단위로 관리된다. ➡️ 만약 쿼리를 통해 1개의 레코드를 읽고 싶더라고 하나의 블록을 읽어야한다.
인덱스 사용을 조심해야 하는 이유가 뭘까?
인덱스가 있으면 데이터 변경 작업(INSERT, UPDATE, DELETE) 시 성능이 나빠진다. 그 이유는 페이지 분할이라는 작업이 발생하기 때문이다.
따라서 인덱스를 사용하는 것이 효율적인지 알아보는 것이 중요하다.
CREATE [UNIQUE] INDEX 인덱스_이름
ON 테이블_이름 (열_이름) [ASC || DESC]
DROP INDEX 인덱스_이름 ON 테이블_이름
기본키(클러스터형 인덱스)
고유키(보조 인덱스)
create index idx_member_addr
on member (addr)
ANALYZE TABLE member;
SHOW TABLE STATUS LIKE 'member';
Index_length를 통해 보조 인덱스가 생성된 것을 확인할 수 있다.
위에서 한 내용 그대로인데 mem_name에 보조 인덱스 하나 더 추가한 모습
SELECT * FROM member;
이 쿼리를 실행하는데 인덱스를 사용하고 있는지 확인하는 방법
결과창 우측의 EXECUTION PLAN 누르면 확인 가능
지금은 책 전부를 살펴본 것과 같은 결과
SELECT mem_id, mem_name, addr FROM member;
왜 아직도 책 전부 보고 있나요 ㅠㅠ
SELECT mem_id, mem_name, addr
FROM member
WHERE mem_name = '에이핑크';
O M G Single Row = 인덱스를 사용해 결과를 얻었다는 뜻
즉, WHERE 절에 열 이름이 들어있어야 인덱스를 사용
인원 수 보조 인덱스 생성
CREATE INDEX idx_member_mem_number
ON member (mem_number);
ANALYZE TABLE member;
인원 수 7명 이상인 그룹의 이름과 인원수 조회
SELECT mem_name, mem_number
FROM member
WHERE mem_number >= 7;
아름답게 인덱스가 사용된 모습....
MySQL은 인덱스 검색할지 테이블 전체 검색할지 구분 가능
💡 인덱스가 사용되지 않으면 비효율적이므로 유지보수에 신경써야함
SHOW INDEX FROM member;
DROP INDEX idx_member_mem_name ON member;
DROP INDEX idx_member_addr ON member;
DROP INDEX idx_member_mem_number ON member;
member 확인
INDEX 확인
엥 왜 갑자기 Cardinality가 10이나 나오지?? ➡️ Cardinality는 고유값의 개수를 알려줘 교재와 다르게 10개가 나오는게 정상인 듯..?
카디널리티는 특정 컬럼을 기준으로
중복도가 높으면 카디널리티가 낮고
중복도가 낮으면 카디널리티가 높다.
테이블 전체 row에서 얼마나 중복되는가에 대한 지표로 활용 가능 -> 상대적인 수치, 실제로 카디널리티에 기반한 인덱싱 전략을 세우기도 함
💡 지금까지 배운대로 뭐가 효율적일지 생각해보자
정답은 카디널리티가 높은 것부터 낮은 순으로 구성하는 것이다.
이유는 B-Tree에 있는데 이 자료구조는 데이터를 일정하게 정렬하고, 나누는 특징이 있다. 데이터가 나뉘면서 Depth가 얕은데 (대부분 3이하) 이 특징이 데이터 조회 성능이 좋은 이유다.
그렇기 때문에 범위를 크게 줄일 수 있는(카디널리티가 높은) 것부터 탐색하는 것이 효율적이다.
인덱스 생성 기본 문법
CREATE [UNIQUE] INDEX 인덱스_이름
ON 테이블_이름 (열_이름) [ASC || DESC]
인덱스 제거 기본 문법
DROP INDEX 인덱스_이름 ON 테이블_이름