根据 COUNT 参数查询不使用索引

问题描述

首先,我创建了一个简单的数据库,其中包含一个 MyISAM 表,其中包含一个名为 feature 的索引字段。

CREATE DATABASE test;
USE test;
CREATE TABLE data(
    id INT(11) NOT NULL AUTO_INCREMENT,feature VARCHAR(64),PRIMARY KEY (id)
) ENGINE=MyISAM;
INSERT INTO data VALUES (1,'a'),(2,'b');
CREATE INDEX data_feature ON data(feature);

然后,当我使用计数测试 GROUP BY 查询时,当 COUNT() 由 id 生成时,它不使用索引(请参阅 Extra 列末尾的EXPLAIN).

MysqL> EXPLAIN SELECT feature,COUNT(1) FROM data GROUP BY feature;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | data  | NULL       | index | data_feature  | data_feature | 259     | NULL |    2 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
1 row in set,1 warning (0.00 sec)

MysqL> EXPLAIN SELECT feature,COUNT(*) FROM data GROUP BY feature;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | data  | NULL       | index | data_feature  | data_feature | 259     | NULL |    2 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------------+
1 row in set,COUNT(id) FROM data GROUP BY feature;
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------+
|  1 | SIMPLE      | data  | NULL       | index | data_feature  | data_feature | 259     | NULL |    2 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-------+
1 row in set,1 warning (0.00 sec)

我已经在 MysqL Community 8.0.21 和 MariaDB 10.3.25 上对其进行了测试。

解决方法

id 要求优化器检查 NOT NULL 是否为 COUNT(*)。标准模式是简单地说 PRIMARY KEY

InnoDB 的工作方式可能有所不同。但这是因为 INDEX(feature) 被隐式添加到任何二级索引的末尾。这使得 INDEX(feature,id) 像 {{1}} 一样工作,在这种情况下,它将是一个“覆盖”索引,如“使用索引”所示。

(在这十年里几乎没有理由坚持使用 MyISAM。)