一、環境準備
mysql InnoDB有下面兩個表:
viewing_number(1814483行數據)
列:id、content_id、sel_count、create_time、update_time
viewing_number_copy(1814483行數據)
列:id、content_id、sel_count、create_time、update_time
索引: update_time
二、觀察與分析(第一組,沒有索引)
觀察
explain select id,update_time from viewing_number v where update_time>="2020-05-27 06:30:55" order by id;
explain select id,update_time from viewing_number v where update_time>="2020-05-27 06:30:55" order by id limit 100;
explain select id,update_time from viewing_number v where update_time>="2020-05-27 06:30:55" order by id limit 10000;
分析
可以發現3次執行計劃是一樣的,都是用到了主鍵索引,並且是在where裏用的。但是where條件裏並沒有用到主鍵……,而是order by用到了。這是什麼原理?
這裏mysql有個優化:
- 如果where沒有用到索引,order by也沒有用到索引
先執行where,全表掃描找出符合條件的行,再按照order by在內存中進行排序。 - 如果where沒有用到索引,但是order by用到索引了
先執行order by,掃描用到的索引,再回表判斷where是否符合條件。 - 如果在2的情況下,有limit
則取夠limit條符合條件的行就返回了,並不會掃描完所有索引。
三、觀察與分析(第二組,有索引)
觀察
explain select id,update_time from viewing_number_copy v where update_time>="2020-05-27 06:30:55" order by id;
explain select id,update_time from viewing_number_copy v where update_time>="2020-05-27 06:30:55" order by id limit 100;
explain select id,update_time from viewing_number_copy v where update_time>="2020-05-27 06:30:55" order by id limit 10000;
分析
可以發現1,3次執行計劃是一樣的,2的執行計劃有點特殊。這是什麼原理?
這裏mysql又有個優化:
- 如果where有索引,order by也有索引
默認情況下,先執行where,掃描用到的索引,找出符合條件的行,再按照order by在內存中進行排序。 - 但是如果在1的情況下,有limit,並且limit比較小
則會先執行order by,掃描用到的索引,再回表判斷where是否符合條件。取夠limit條符合條件的行就返回了,並不會掃描完所有索引。
四、總結
對比三、四小節,可以看出:加索引之後,部分情況下,掃描的行數還變多了,並且使用了內存排序。
所以,加索引不是萬能的,不要想當然,要根據實際業務進行分析和測試。
參考
《sql查詢調優之where條件排序字段以及limit使用索引的奧祕》
《sql order by與索引之間的關係(where條件出現字段纔有效)》