mysql 组合索引只用了一部分也能用上索引?

问题如下:有一个表,总行数为21万,其中只有一个组合主键索引 primary key (channel_app_id, content_app_id)

create table t_channel_apply
(
  channel_app_id    varchar(64)  default ''                    not null comment '渠道方appid',
  content_app_id    varchar(64)  default ''                    not null comment '内容方appid',
   apply_state       tinyint(2)   default 0                     not null comment 
  created_at        timestamp    default '0000-00-00 00:00:00' not null comment '创建时间',
  updated_at        timestamp    default CURRENT_TIMESTAMP     not null comment '更新时间,有修改自动更新',
  primary key (channel_app_id, content_app_id)
)
  comment '渠道申请信息表';

我的查询语句是,只用到了content_app_id

select count(content_app_id) from `t_channel_apply` where `content_app_id` = 'xxx'

如我们周知,mysql的组合索引都是左匹配的原则,即假如组合索引(a,b,c)

a,
a,b
a,b,c 
c,b,a
c,a,b
b,a
...
//左匹配并且因为索引位置可以随意替换,故以上都会用到索引
b,c
//如果不能左匹配就无法使用索引

但我 explain select count(content_app_id) from t_channel_apply where content_app_id = ‘xxx’,发现这个语句竟然用到了索引,这个真是颠覆了我的认知

ok,开始慢慢分析

首先我注意到,不管我的content_app_id查询值是什么,rows都不会变,固定是86548,这个奇怪的数字
根据以往的知识 explain 中的 rows 的意思是mysql预估要得到结果要查询的行数,然后才会真正执行sql语句,所以这个值只能做参考。
然后我尝试更改语句来对比。

使用 select count(apply_state) from t_channel_apply where content_app_id = ‘xxx’ and apply_state = 0;
使用 select count(content_app_id) from t_channel_apply where apply_state = 0;
使用 select count(apply_state) from t_channel_apply where content_app_id = ‘xxx’;,

以上语句都会全表查找,所以就想到查询条件和查询字段都是索引的情况就会使用到, 这样的情况不就符合了覆盖索引的条件吗?

所以得出了结论,就是即使组合索引只用了一部分也能用上索引是对的,前提是符合覆盖索引的条件

所以可以得出 86548 其实就是索引的行数,mysql预估的时候其实预估查询索引的行数,虽然真正运行并不准确

ps:

在尝试多次查询中,explain 中的 extraImpossible WHERE noticed after reading const tables
网上解释是根据主键查询或者唯一性索引查询,如果这条数据没有的话,它会全表扫描
在 MySQL 5.7.17 下就会显示 no matching row in const table,这样就好理解多了

这样的结果比较少见,记录一下

参考资料:
https://yq.aliyun.com/articles/393774

2020-12-28 哈哈哈,这个真的有趣,我现在才意识到为什么使用了部分组合索引explain也会显示使用了索引,
其实是因为是覆盖索引的原因,所以只遍历了索引树
所以explain才会显示说使用了索引


版权声明:本文为luo1324574369原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。