前言
辣鸡的我写索引优化作业遇到一个很奇怪的问题。
大概就是,在500w行数据的order表中,找出年龄小于20order列表,看能否使用索引进行查询优化。
创建索引、查询时间、查询计划一套做下来,发现优化器没有用创建的索引。于是开始寻找问题。
过程
首先很自然地用下面的语句进行测试
1 | select * from orders where age < 20; |
发现在没加索引的时候,查询时间,explain计划如下
加了个单列普通索引
1 | alter table orders add index ageindex(age); |
再执行语句发现,查询时间和explain计划没变,说明优化器没有使用新建的索引。
强制使用索引,加上force index(ageindex)
,获得查询时间和explain结果如下
图中可见,索引确实让过滤数值和row值都优化了,但是时间却大大增加了,而传输时间更是多了太多。
接着做第二题,查找姓王的人,类似的题目。但是不管用普通索引还是全文索引,优化器都不用索引。
后来改换思路,把要查询语句改成只返回主键
1 | select id from orders where age < 20; |
突然峰回路转,索引被使用,查询时间立刻降低
原来select *
才是罪魁祸首
深入
大佬说了,select* 杜绝了覆盖索引的可能性。虽然上面的索引在查询计划里看起来过滤了大量数据,但
首先通过辅助索引过滤数据,然后通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。首先通过辅助索引过滤数据,然后通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。
磁盘io导致查询开销陡增,反倒不如全表顺序查询时间少。当索引节约的成本能以抵消、甚至远远低于磁盘io要付出的代价时,优化器自然选择放弃索引。
所以假如要求是select *,在不考虑维护的情况下,不如建立包含全列的多列索引。
最后
索引是个很重要的优化方法,经过这么多年的发展,网上已经有很多各种经验之谈,不过了解原理还是很重要啊。
《高性能mysql》得好好看一看才行。