mysql5.6 分頁查詢優化
mysql5.6 分頁查詢優化
場景:
表結構:主鍵(非自增)contentCode(varchar),過濾條件列為updateTime(timeStamp),已經為timestamp建立索引。
搜尋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之後的版本貌似得到了解決。
優化:總體思路是走索引,走索引,還是走索引。
首先我們通過分頁條件查詢,只走updateTime索引,然後獲取所有的主鍵,此時mysql是不回主表的。然後通過in 查詢主表中所有在此範圍的資料。
參考 https://www.cnblogs.com/lpfuture/p/5772055.html
但是,可惜的是,會有如下問題:
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為:
偽表 表連線
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 );
in 裡面 用limit 的sql:
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語句的完整執行順序
1、from子句組裝來自不同資料來源的資料;
2、where子句基於指定的條件對記錄行進行篩選;
3、group by子句將資料劃分為多個分組;
4、使用聚集函式進行計算;
5、使用having子句篩選分組;
6、計算所有的表示式;
7、使用order by對結