mysql5.6 分頁查詢優化html
場景:mysql
表結構:主鍵(非自增)contentCode(varchar),過濾條件列爲updateTime(timeStamp),已經爲timestamp創建索引。sql
搜索sql爲:函數
SELECT * FROM my_hello_table WHERE updateTime >= '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000
問題:數據在分頁到60w後,分頁查詢時間爲5.8s左右。沒法忍受。測試
緣由:雖然走了索引,但mysq5.6 對於分頁的操做是先根據過濾條件去索引查詢出全部的updateTime,而後根據updateTime依次查詢出60w數據,而後拋棄前59w9k條查詢出數據,而後獲取最後的1k條。優化
分頁的這種越到後面用時越長的問題,是mysql5的一個失誤,在mysql8以後的版本貌似獲得瞭解決。code
優化:整體思路是走索引,走索引,仍是走索引。htm
首先咱們經過分頁條件查詢,只走updateTime索引,而後獲取全部的主鍵,此時mysql是不回主表的。而後經過in 查詢主表中全部在此範圍的數據。blog
參考http://www.javashuo.com/article/p-qefdncmw-dz.html排序
有以下sql:
SELECT * FROM my_hello_table WHERE contentCode IN ( SELECT contentCode FROM my_hello_table WHERE updateTime > '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000 ) );
可是,惋惜的是,會有以下問題:
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
解決方法有 僞表進行錶鏈接操做 和 in裏面使用limit 參考:
https://www.cnblogs.com/c-h-y/p/9946813.html
最後 的sql爲:
in 裏面 用limit 的sql:
SELECT * FROM my_hello_table WHERE contentCode IN ( SELECT t.contentCode FROM ( SELECT contentCode FROM my_hello_table WHERE updateTime > '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000 ) AS t );
僞表 錶鏈接
SELECT a.* FROM my_hello_table a INNER JOIN ( SELECT contentCode FROM my_hello_table WHERE updateTime > '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000 ) AS b ON a.contentCode = b.contentCode
兩種方式推薦第二種。避免了in語句。進行explain診斷會發現第二種效率高不少。
最後通過測試,查詢時間由原來的5.8秒 優化到1.2s左右,優化率搞到400%。
記錄下sql語句的完整執行順序
一、from子句組裝來自不一樣數據源的數據;
二、where子句基於指定的條件對記錄行進行篩選;
三、group by子句將數據劃分爲多個分組;
四、使用匯集函數進行計算;
五、使用having子句篩選分組;
六、計算全部的表達式;
七、使用order by對結果集進行排序。