今天碰到一个MySQL索引失效的问题,想当年面试,面试官问我有没有遇到过索引失效的场景时,我羞涩的答了一个“没有”,甚是尴尬。如今也遇到了MySQL优化器判断失误的时候,特此记录下来,以备下次面试时吊打面试官。

记录问题

tb_order 表有索引

mysql给时间加索引 mysql 时间索引失效_数据


搜索时条件也没有违反索引规则,显示可以使用索引,但却没有实际使用。

mysql给时间加索引 mysql 时间索引失效_数据_02


强制使用 idx_contract_time 索引,发现是可以提高查询速度的。

mysql给时间加索引 mysql 时间索引失效_mysql_03


或者将pay_amount字段加进索引中,也可以走索引

mysql给时间加索引 mysql 时间索引失效_辅助索引_04


mysql给时间加索引 mysql 时间索引失效_辅助索引_05


查询资料

即使存在辅助索引idx_contract_time, 优化器最后可能还是选择primary聚集索引。

原因是:用户选取的数据是需要整行信息,而idx_contract_time索引不能覆盖到我们要查询的信息,因此在对idx_contract_time索引查询到指定数据后,还要再进行一次回表访问来查找整行的信息。

虽然idx_contract_time索引中数据是顺序存放的,但是再进行一次书签查找的数据则是无序的,变成了磁盘上的离散读操作。如果访问的数据量很小,那优化器还是会选择辅助索引,但访问的数据占整个表蛮大一部分时(一般20%),优化器会选择通过聚集索引来查找数据,因为顺序读的操作会远大于离散读。

如果不能使用覆盖索引的情况,优化器只有数据量小的时候才会使用辅助索引。这是由传统的机械硬盘特性决定的。若使用固态硬盘,随机读操作很快,且有足够的自信能确认使用辅助索引可以带来更好的性能,可以使用Force index强制使用某个索引。

mysql在扫描情况下会选择全表扫描而不是走索引、mysql优化器选择使用或者不用索引

其他引起失效原因

后端程序员必备:索引失效的十大杂症