首先,选择索引是优化器的工作。优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句。在数据库里面,扫描行数是影响执行代价的因素之一;扫描的行数越少,意味着访问的磁盘数据的次数越少,小号的CPU资源越少。优化器还会结合是否使用临时表、是否排序等因素进行综合判断。

1.扫描行数是怎么判断的?

show index;

cardinality列代表的是对应索引的基数。这个值并不准确,mysql是通过采样统计得到的结果值,InnoDB默认会选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。而数据表是会持续更新的,索引统计信息也不会固定不变。所以,当变更的数据行数超过1/M的时候,会自动触发重新做一次索引统计。在mysql中,有两种存储索引统计的方式,可以通过设置参数innodb_stats_persistent的值来选择。设置为on的时候,表示统计信息会持久化存储,这时默认的N是20,M是10。设置为off时,统计信息只存在内存中。这时,默认N是8,M是16。故而有可能会造成优化器选错索引。

除了基数外,优化器还要考虑是否需要回表等的代价,如果某个索引基数跟主表基数差别不是非常大,且该查询语句如果需要回表查询,优化器往往会考虑到回表的成本而直接使用主键索引。可以使用force index(a) 来强制使用a索引。

如果使用explain 查到的rows跟mysql统计的基数差值很大,也可以及时矫正。

analyze table t;

特殊情况下,也可以删掉吴用的索引,或者新建一个更合适的索引。不太建议的办法是,修改mysql语句,引导其使用我们期望的索引。

发表评论

电子邮件地址不会被公开。 必填项已用*标注