인덱스 레인지 스캔
커버링 인덱스
라고 한다. 커버링 인덱스로 처리되는 쿼리는 디스크의 레코드를 읽지 않아도 되기 때문에 I/O 가 상당히 줄어든다.인덱스 풀 스캔
루스 인덱스 스캔
SELECT dept_no, MIN(emp_no)
FROM dept_emp
WHERE dept_no BETWEEN 'd002' AND 'd004'
GROUP BY dept_no
ALTER TABLE gunpla ADD INDEX idx_grade_created_at (grade, created_at)
#인덱스 안탐
SELECT grade, created_at FROM gunpla WHERE created_at >= '2019-01-01'
#인덱스 탐
SELECT grade, created_at FROM gunpla WHERE grade = 'MG' AND created_at >= '2019-01-01'
위 쿼리문 처럼 두 가지의 비교 조건을 가진 2번째 쿼리는 인덱스를 사용하지만 1번째 쿼리는 grade에 대한 비교조건이 들어 있지 않아서 인덱스를 효율 좋게 사용할 수 없었는데 이런 경우 created_at 을 첫 번째로 하는 인덱스를 만들어줘야 했다고 한다.
MySQL 8버전부터는 옵티마이저가 grade 컬럼을 건너뛰어서 created_at 컬럼만으로도 인덱스를 탈 수 있게 해주는 인덱스 스킵 스캔(Index Skip Scan)
이 등장했다.
인덱스 스킵 기능을 사용하지 않으면 인덱스를 타긴 하나 인덱스 풀 스캔이 발생해서 그다지 효율적으로 검색할 수 없다.
생긴지 얼마 안돼서 몇 가지 제약조건이 있는데, 조건절에 없는 인덱스의 유니크한 값이 적어야 하고 쿼리가 인덱스에 존재하는 컬럼만으로 끝나야 한다. 그래서 인덱스 스킵 스캔은 인덱스의 첫 번째 컬럼의 유니크 한 값이 적을 때에만 적용이 가능한 최적화 방법이다.
SELECT * FROM gunpla WHERE grade = 'MG' AND created_at >= '2019-01-01'
CREATE INDEX idx_name_price ON gunpla (name ASC, price DESC)
인덱스 생성 시점에 오름차순 혹은 내림차순으로 정렬이 결정된다.
인덱스를 사용하는 시점에 인덱스를 읽는 방향에 따라서 오름차순 혹은 내림차순으로 정렬하는 효과를 얻을 수 있다.
오름차순으로 만들어진 인덱스를 역방향으로 읽으면 내림차순이 되는 것이다. 반대도 마찬가지 name의 인덱스가 오름차순으로 되어 있다고 가정하면
SELECT * FROM gunpla WHERE name >= 'RX-78-3' ORDER BY name ASC LIMIT 6
SELECT * FROM gunpla ORDER BY name DESC LIMIT 8
첫 번째 쿼리는 name에 정의된 인덱스를 통해 G-3건담을 찾은 후 정방향으로 인덱스를 읽으면서 5개의 레코드만 가져오면 된다. 두 번째 쿼리는 인덱스를 역방향으로 읽으면서 8개만 가져오면 된다.
MIN(), MAX() 와 같은 함수 최적화가 필요한 경우에도 옵티마이저가 자동으로 읽기 방향을 전환하여 실행 계획을 만들어낸다.
복합 인덱스에서는 각각의 컬럼이 내림차순, 오름차순이 혼합되어 있는 경우 내림차순 인덱스로만 사용할 수 있다.
더미로 7239680건 정도를 집어넣은 테이블로 테이블을 풀 스캔하면서 정렬만 수행하는 쿼리를 실행해보면
SELECT * FROM test ORDER BY id ASC LIMIT 7239679 1
#3.31 sec
SELECT * FROM test ORDER BY id DESC LIMIT 7239679 1
#4.52 sec
첫 번째 쿼리보다 두 번째 쿼리가 시간이 좀 더 걸린다는 것을 알 수 있는데 InnoDB 에서 정방향 스캔보다 역방향 스캔이 느릴 수 밖에 없는 이유가 2가지 있다. 첫 번째는 페이지의 잠금이 정방향 스캔에 적합한 구조로 되어있고 두 번째는 페이지 내 인덱스들의 레코드가 단방향으로만 연결이 되어 있다.
일반적으로 인덱스를 내림차순 하는 쿼리가 별로 없다면 내림차순 인덱스를 고려할 필요는 없을 것 같다.
게시판 같은 경우 가장 최신글이 먼저 올라와야 하니까 내림차순 인덱스를 고려하는 것이 좋을 것 같다.
자주 사용되는 정렬의 형태로 인덱스를 만들어놓으면 쿼리의 병목현상 완화에 도움이 될 것 같다.