MySQL/MariaDB中COUNT参数是否影响GROUP BY查询的覆盖索引使用
MyISAM场景下覆盖索引差异的核心原因
1. MyISAM的基础索引存储结构
- MyISAM采用索引与数据完全分离的存储架构:主数据文件按行存储全表所有列的实际值,所有索引文件(包括主键索引、二级普通索引)的叶子节点仅存储「索引列值 + 对应行在数据文件中的物理位置指针」。
- 这和InnoDB的聚簇索引结构有本质区别:InnoDB的二级索引叶子节点会直接存储主键值,而MyISAM的二级索引不会存储任何非索引列的实际值。
2. 覆盖索引的判定规则
- 所谓覆盖索引,指查询执行过程中需要的所有数据,都可以直接从当前遍历的索引结构中获取,不需要回表读取主数据文件的行内容,此时EXPLAIN的Extra列会显示
Using index。
3. 三类COUNT语法的执行逻辑差异
COUNT(*)、COUNT(1)的语义是统计聚合组内的总行数,引擎实现上不需要读取任何具体列的实际值——只要遍历到索引中的条目,就可以直接计数,不需要回表。
本次测试中遍历data_feature二级索引时,本身就持有所有需要的feature列值(用来完成GROUP BY分组),同时不需要读取其他列的值就能完成计数,完全满足覆盖索引的要求,因此Extra列显示Using index。COUNT(id)的语义是统计id列值不为NULL的行数,哪怕当前id列被定义为NOT NULL主键,数据库执行时也会严格遵循聚合函数的语义,需要逐行读取id列的实际值完成判断,才能输出正确的计数结果。
而MyISAM的data_feature二级索引叶子节点中,根本没有存储id列的实际值——只有指向行位置的指针,要拿到id的值必须回表读取主数据文件。这就导致查询需要的id列值无法从当前使用的索引中直接获取,自然不满足覆盖索引的判定条件,因此Extra列不会显示Using index。
补充说明:如果把表引擎换成InnoDB,相同的
COUNT(id)查询是可以触发覆盖索引的——因为InnoDB的二级索引自带主键值(也就是这里的id),不需要回表就能拿到id的值完成判断,自然可以匹配覆盖索引规则。
内容的提问来源于stack exchange,提问作者Carlos Roldán
相关产品推荐
相关产品推荐

