Покрывающий индекс — это особый случай индекса в InnoDB, когда все необходимые поля для запроса включены в индекс, как упоминалось в этом блоге https://blog.toadworld.com/2017/04/06./ускорение-ваших-запросов-использование-покрывающего-индекса-в-mysql.
Но я столкнулся с ситуацией, когда покрывающий индекс не используется, когда SELECT и WHERE включают только индексированные столбцы или первичный ключ.
Версия MySQL: 5.7.27
Пример таблицы:
mysql> SHOW CREATE TABLE employees.employees\G;
*************************** 1. row ***************************
Table: employees
Create Table: CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` enum('M','F') NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`),
KEY `first_name_last_name` (`first_name`,`last_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Ряды: 300024
Индексы:
mysql> SHOW INDEX FROM employees.employees;
+-----------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| employees | 0 | PRIMARY | 1 | emp_no | A | 299379 | NULL | NULL | | BTREE | | |
| employees | 1 | first_name_last_name | 1 | first_name | A | 1242 | NULL | NULL | | BTREE | | |
| employees | 1 | first_name_last_name | 2 | last_name | A | 276690 | NULL | NULL | | BTREE | | |
+-----------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
mysql> EXPLAIN SELECT first_name, last_name FROM employees.employees WHERE emp_no < '10010';
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | employees | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 9 | 100.00 | Using where |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Как видно, first_name
и last_name
в предложении SELECT являются индексированными столбцами, а emp_no
в предложении WHERE — первичным ключом. Но план выполнения показывает, что строки результатов извлекаются из первичного индексного дерева.
На мой взгляд, он должен сканировать дерево вторичных индексов и фильтровать результаты по emp_no < '10010'
, в котором используется покрывающий индекс.
Изменить
Кроме того, я видел, что покрывающий индекс используется в той же ситуации в MySQL 5.7.21.
Строки:8204
SQL:
explain select poi_id , ctime from another_table where id < 1000;