问题描述
首先,我创建了一个简单的数据库,其中包含一个 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。)