possible_keys, key

possible_keys는 mysql이 테이블에서 사용할 수 있는 인덱스 후보들을 말한다. key는 실제로 테이블을 읽을때 사용한 인덱스를 말함. 즉 중요한건 key임. 참고로 innodb는 비용기반으로 가장 적은 비용이 드는 인덱스를 후보중에서 고른다.

한편 possible_keys에 후보들이 있는데 실제로 아무런 키가 사용되지 않는 경우도 있다.

EXPLAIN SELECT * FROM product WHERE category_id > 0;

image.png

인덱스가 있어도 풀 테이블 스캔을 사용하는 이유, 어차피 읽을 행이 너무 많으면 인덱스를 통해 원 데이터를 찾아가는 과정(이 과정은 랜덤 I/O로 일어난다.)이 너무 잦아서 이 오버헤드를 줄이기 위해 그냥 처음부터 원본 데이터를 찾아가버린다. 읽어야할 행이 전체의 20~30% 이상 정도 되면 이런 전략을 택해버림. 왜? 풀테이블 스캔은 순차 I/O에 가깝기 때문. 오버헤드가 거의 없다.

한편 후보에는 없는데도 인덱스를 사용하는 케이스도 있다. 즉 possible_keys는 null인데 key에 인덱스가 잡혀있음.

EXPLAIN SELECT member_id FROM orders;

image.png

이건 옵티마이저가 커버링 인덱스를 사용할때 발생함. where절에 인덱스를 포함하지 않아서 후보키에는 인덱스가 없지만, 결국 셀렉트하는 컬럼이 전부 인덱스에 포함되어있으니, 옵티마이저가 스스로 최적화해서 그냥 인덱스만 읽자고 판단한 것임.

key_len

복합 인덱스에서 몇개 컬럼을 활용했는가를 나타낸다. 엄밀히는 사용된 인덱스 키의 바이트 길이임. 이 값을 이용해 복합 인덱스에서 몇개의 컬럼을 사용했는지 역으로 연산할 수 있다.

그런데 귀찮은건 이건 알기 위해선 데이터 타입별 바이트 크기를 대강 알고 있어야 함. 참고로 실제 담겨있는 데이터의 실제 길이는 아님. 만약 이랬다면 타입이 varchar라면 일일이 계산해야 한다. 이렇지 않고, key_len은 해당 인덱스의 데이터 타입이 가질 수 있는 최대 키 길이를 기준으로 계산된다.

여기에는 다음의 규칙이 있다.

image.png

vachar는 다음의 규칙을 따른다.

vacher(n)일 경우, 4 * n + 2