MySQL大數據量分頁查詢方法及其優化


 

摘抄自:https://mp.weixin.qq.com/s?__biz=MzkxMDI2NTc2OQ==&mid=2247485241&idx=1&sn=3330bf2abc82a857692aaee316824d90

limit偏移量不變,隨着查詢記錄量越來越大,所花費的時間也會越來越多。

limit查詢記錄數不變,隨着查詢偏移的增大,尤其查詢偏移大於10萬以后,查詢時間急劇增加。

原因分析

select * from user where sex = 1 limit 100,10

由於 sex 列是索引列,MySQL會走 sex 這棵索引樹,命中 sex=1 的數據。

然后又由於非聚簇索引中存儲的是主鍵 id 的值,且查詢語句要求查詢所有列,所以這里會發生一個回表的情況,在命中 sex 索引樹中值為1的數據后,拿着它葉子節點上的值也就是主鍵 id 的值去主鍵索引樹上查詢這一行其他列(name、sex)的值,最后返回到結果集中,這樣第一行數據就查詢成功了。

最后這句 SQL 要求limit 100, 10,也就是查詢第101到110個數據,但是 MySQL 會查詢前110行,然后將前100行拋棄,最后結果集中就只剩下了第101到110行,執行結束。

小結一下,在上述的執行過程中,造成 limit 大偏移量執行時間變久的原因有:

  • limit a, b會查詢前a+b條數據,然后丟棄前a條數據

MySQL數據庫的查詢優化器是采用了基於代價的方式,而查詢代價的估算是基於CPU代價IO代價。如果MySQL在查詢代價估算中,認為全表掃描方式比走索引掃描的方式效率更高的話,就會放棄索引,直接全表掃描。

 

優化方式

t5表有200萬數據,id為主鍵,text為普通索引

使用覆蓋索引

如果一條SQL語句,通過索引可以直接獲取查詢的結果,不再需要回表查詢,就稱這個索引為覆蓋索引。

在MySQL數據庫中使用explain關鍵字查看執行計划,如果extra這一列顯示Using index,就表示這條SQL語句使用了覆蓋索引。

讓我們來對比一下使用了覆蓋索引,性能會提升多少吧。

沒有使用覆蓋索引

select * from t5 order by text limit 1000000, 10;

這次查詢花了3.690秒,讓我們看一下使用了覆蓋索引優化會提升多少性能吧。

使用了覆蓋索引

select id, `text` from t5 order by text limit 1000000, 10;

從上面的對比中,超大分頁查詢中,使用了覆蓋索引之后,花了0.201秒,而沒有使用覆蓋索引花了3.690秒,提高了18倍多,這在實際開發中,就是一個大的性能優化了。

 

子查詢優化

因為實際開發中,用SELECT查詢一兩列操作是非常少的,因此上述的覆蓋索引的適用范圍就比較有限。

所以我們可以通過把分頁的SQL語句改寫成子查詢的方法獲得性能上的提升。

select * from t5 where id>=(select id from t5 order by text limit 1000000, 1) limit 10;

其實使用這種方法,提升的效率和上面使用了覆蓋索引基本一致。

但是這種優化方法也有局限性:

  • 這種寫法要求主鍵ID必須是連續的

  • Where子句不允許再添加其他條件

 

延遲關聯

和上述的子查詢做法類似,我們可以使用JOIN,先在索引列上完成分頁操作,然后再回表獲取所需要的列。

select a.* from t5 a inner join (select id from t5 order by text limit 1000000, 10) b on a.id=b.id;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM