忽略idx_1和idx_city_id_type这两个索引的重复。 这是历史遗留下来的问题。
“我知道有idx_city_id_type和idx_1的索引”,我们的查询条件是city_id和type,两个索引都可以去。
但是,我们的查询条件真的要考虑city_id和type吗? (机智的小伙伴应该注意到了问题点。 先往下说,让大家想想)
既然有索引,接下来就需要看那个句子是否实际达到了索引。 MySQL提供了Explain可以分析SQL语句。 Explain用于解析SELECT查询语句。
Explain中的重要字段包括
select_type :查询类型。 简单查询、联接查询、子查询等等
key :使用的索引
rows :将扫描的行数
更详细的Explain介绍可供参考: MySQL性能优化神器Explain使用分析
执行联合索引后,实际执行时间0.00175714s不再是行查询。
发现了问题并总结了。 “对于limit 1,MySQL优化程序认为主键索引可以更快地找到该数据,联合索引必须扫描和排序该索引,主键索引是天生有序的,并且将主键索引视为实际上,MySQL扫描了8000w的数据,但是因为当天找不到选择的人(满足条件的数据),所以浪费了很多时间。
首先,您必须知道选择索引是MySQL优化程序的工作。
优化程序选择索引的目的是找到最佳执行方案,并以最低的成本执行语句。 在数据库中,扫描行数是影响执行成本的因素之一。 扫描的行数越少,表示访问磁盘数据的次数越少,消耗的CPU资源越少。
“当然,扫描行数不是唯一的判断标准,优化程序会综合判断是否使用临时表、是否排序等要素。 「」
总而言之,优化程序的选择有很多考虑事项:“是否扫描行数、是否使用临时表、是否重新排序等”
为什么要进行统一修订呢? 对整个表逐行进行修订,可以得到准确的结果,但由于成本过高,只能选择“采样修订”。
在对集成采样时,InnoDB默认选择n个数据页,以对这些页上的不同值进行集成以获得平均值,并乘以该索引的页数,从而获得该索引的基数。数据表不断更新,索引统一修订也不固定。 因此,如果更改的数据行数超过1/M,则会自动触发索引集成修订的重新创建。
在MySQL中,有两种方法可以通过设置参数innodb_stats_persistent的值来保存索引集成修订。
如果设置为on,则表示永久存储统一修订信息。 此时,隐式的n是20,而m是10。
设定为off时,表示统一修正信息仅保存在存储器中。 此时,隐式的n是8,而m是16。
由于是取样统一校正,不管n是20还是8,该基数都容易不准确。
可以使用analyze table t命令重新修改索引信息。 但是,这个命令生产环境需要与DBA联系,所以我不做实验,大家可以自己进行实验。