背景
新上线的一个功能,在测试环境正常,生产环境很慢,explain后发现,没有走索引,相关字段确实没有索引,遂建立索引,测试环境走索引查询正常,生产环境一直没走。
排查
再次执行explain方法后发现,possible_keys有目标索引,key 还是为空,考虑还是mysql选择器的问题,我们知道mysql拿到我们的sql后会进行逻辑优化,基于成本来选择时候走索引。
到表数据里查询新增索引字段的值的不重复个数,为0, 这是一个新使用的字段,刚上线还没有业务数据,那我感觉自己就知道了为啥没走索引了,连值都没有B+树咋建立的,走个屁哦。自信满满抓紧造几条测试数据,结果还是没走……。这是咋回事嘞
强制走索引
使用force index(index_name) 强制走索引,(force index 紧跟from后的表名后),发现可以走索引了,但是不想发版,pass
刷新索引数据
使用show index from table 命令
发现新建的索引有个Cardinality 的值为 1,不对劲,其他俩个的值咋都这么大,查一下这个含义
Google告诉我
大概意思是,在mysql中,术语cardinality表示放入列中的数据的唯一性,它是一个影响搜索,聚合,排序的属性。
- 低区分度:所有的值都一样
- 高区分度:所有的值都不一样
- 原文在这下边还有个小例子 www.tutorialspoint.com/what-is-car…
MySQL官方文档说到
他是一个索引中不同值的预估数量,想更新这个值的话执行
analyze table命令, 它是基于统计的以整型的形式存储,所以及时是小表的话这个数值也不一定准确,值越高,mysql用索引去进行连接查询时使用该索引的机会越大
这就不得了了,这个玩意影响搜索,那为什么我加了数据它也不更新呢,其实我们想这个东西肯定不是实时的,毕竟它也说了自己是个预估值,当然上边已经给了语句我们试一下
使用analyze table tableName
执行过这个sql后发现值果然更新了
去掉
force index 后发现也可以走索引了
是否自动更新索引
那么索引是否会自动更新呢,答案是肯定的,在mysql文档dev.mysql.com/doc/refman/… 中我们可以知道相关描述,主要影响更新的参数是
show variables like 'innodb_stats_persistent'
该参数有两个值
参数表示统计数据是否被持久化到磁盘,当时一般情况下我们是要持久化到磁盘的,值不一样的时候更新统计数据的方式也是不一样的
这里边还有一个参数innodb_stats_auto_recalc ,默认打开,可以看出来,如果操作的行数超过了表总数的10%的话,会自动执行统计,然后统计也不是实时的,如果需要立即更新,使用ANALYZE TABLE 命令
结论
当mysql没有走预估的索引的时候
- 使用
force index - 执行
analyze table