索引失效的几种场景

    在数据库SQL优化中,百分之80%的问题SQL都可以通过索引来解决,但是有时候我们也会碰到一种情况,明明索引都有,为什么MySQL没有选择走索引而是走了全表扫描呢?近期就碰到一个案例,同大家分析一个当时的解决思路以及对索引失效的几种情况总结一下~

一、告警发现

    在一个风和丽日的下午,突然一条高亮的钉钉信息抖动在为眼前。【尊敬的用户xxx,您的数据库实例rm-aabbcc,有告警产生:MySQL CPU使用率>= 90, now is 99.0,请及时处理。】呐尼!数据库CPU报警了!!!

二、问题排查

    1、不管三七二十一,接收到报警信息的第一反应都是立马登录阿里云控制管理台,去抓问题现场!登上去后可以看到数据库会话已经出现了堆积,所有SQL的执行时间都比较长,且全部在Sending data的状态。
索引失效的几种场景_第1张图片


    2、SQL执行效率很差,抓取其中一条SQL,登录数据库查看执行计划,查看慢究竟慢在了哪里,另外建议开发同学排查该SQL属于哪块儿业务,同时我们对SQL执行计划进行分析:
索引失效的几种场景_第2张图片


    从这个执行计划中我们可以一眼看到问题,p表与s表关联是本可以走s表的主键索引,但是却选择走了全表扫描,MySQL为什么会这样做呢?MySQL为什么会认为走ALL的效率会很好??我们可以通过force index来强制SQL走主键索引,看SQL效率是否有提升。
索引失效的几种场景_第3张图片
索引失效的几种场景_第4张图片
_


    通过force index强制SQL走主键索引进行关联后,SQL执行效率提升显著。所以,MySQL此时默认的执行计划是错误的。所以我们想要解决这个问题,必然要分析清楚为什么索引会失效。


    3、表的字符集格式以及排序方式一致,排除隐式转换导致的索引失效。继续往后面看,发现spu表的table_rows为0???排查到这里问题原因基本找到,spu表的统计信息有误导致MySQL执行计划选择错误。建议业务方先把堆积的SQLkill掉缓解数据库的压力。
_


    当数据库负载降下来后,我们再次核实一下我们的猜想是否正确,实际上该表有50w的数据量,但是统计信息却是0,所以误导MySQL认为走ALL的效率也是很快的,而SQL实际执行下来扫描数据量很大,SQL执行效率极差。
索引失效的几种场景_第5张图片

三、问题处理

    表数据量不大,数据库当前负载也不高,建议直接analyze table tbl_name来重新统计表信息。
_


    重新统计表信息后,我们再次观察统计信息和执行计划,spu的table_rows进行了更正,且执行计划在不加force的情况下选择走了主键索引进行表关联,SQL执行效率恢复正常。
索引失效的几种场景_第6张图片
索引失效的几种场景_第7张图片

四、总结

    以上是整个问题排查以及处理的流程,那么究竟什么情况会导致索引失效呢?我这边大致想到了三种情况:
1、使用函数

where date(create_at) = '2019-01-01'

2、表关联字符集格式以及排序方式不一致

1.关注CHARSET和COLLATION
2.SQL写法错误导致的索引失效比较常见的例子是,我们存储手机号的字段格式为varchar,但是SQL却写的where phone=123;

3、统计信息不准确

本案例

你可能感兴趣的:(索引失效的几种场景)