1. 程式人生 > >mysql5.6 分頁查詢優化

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對結