A covering index is a special case of an index in InnoDB where all required fields for a query are included in the index, as mentioned in this blog https://blog.toadworld.com/2017/04/06/speed-up-your-queries-using-the-covering-index-in-mysql.
But, I encountered a situation that the covering index is not used when SELECT and WHERE only includes indexed columns or primary key.
MySQL version: 5.7.27
Example table:
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
Rows: 300024
Indexes:
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)
As can be seen, the first_name
and last_name
in the SELECT clause are indexed columns, and the emp_no
in the WHERE clause is primary key. But, the execution plan shows that the result rows is retrieved from primary index tree.
In my opinion, it should scan the secondary index tree, and filter results by emp_no < '10010'
, in which the covering index is used.
Edit
Besides, I have seen the covering index is used in the same situation under MySQL 5.7.21.
Rows:8204
SQL:
explain select poi_id , ctime from another_table where id < 1000;