1. 程式人生 > >MySQL查詢優化之limit查詢的優化

MySQL查詢優化之limit查詢的優化

原文地址:https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html

譯文:

8.2.1.17 LIMIT查詢優化

如果你只需要結果集中特定數量的行,可以在查詢中使用LIMIT語句,而不是取出整個結果集然後扔掉一些額外的資料。

MySQL經常優化含有LIMIT row_count子句而沒有HAVING子句的查詢:

    1)如果你使用LIMIT查詢出少量的行,MySQL在一些情況下會使用索引,而通常情況下它更喜歡使用全表掃描;

    2)如果將LIMIT row_count與ORDER BY結合使用,MySQL會在找到排序結果的第一個row_count數量的行後立即停止排序,而不是對整個結果進行排序。如果排序是通過使用索引完成的,這會非常快。如果必須進行檔案排序,那麼將選擇與查詢匹配的所有行(沒有LIMIT子句),並在找到第一個row_count數量的行之前對它們中的大部分或全部進行排序。在找到初始行之後,MySQL不會對結果集的任何剩餘行進行排序;

    這種行為的一種表現是,帶LIMIT和帶LIMIT的ORDER BY查詢可能以不同的順序返回行,如本節後面所述;

    3)如果將LIMIT row_count與DISTINCT結合使用,MySQL會在找到row_count數量的唯一行時立即停止;

    4)在某些情況下,可以通過讀取有序索引(或在索引上進行排序)來解析GROUP BY,然後計算摘要,直到索引值發生變化。在這種情況下,LIMIT row_count不會計算任何非必須的GROUP BY值;

    5)MySQL一旦向客戶端傳送了所需的行數,就會中止查詢,除非使用SQL_CALC_FOUND_ROWS。在這種情況下,可以使用SELECT FOUND_ROWS()檢索行數。具體可參考

Section 12.15, “Information Functions”

    6)LIMIT 0快速返回一個空結果集。這對於檢查查詢的有效性非常有用。還可以使用它來獲取應用程式中結果列的型別,這些應用程式使用MySQL API使結果集元資料可用。使用mysql客戶端程式時,可以使用--column-type-info選項來顯示結果列型別;

    7)如果伺服器使用臨時表來解析查詢,它將使用LIMIT row_count子句來計算需要多少空間;

    8)如果索引不用於ORDER BY,但是還提供了一個LIMIT子句,優化器可能會避免使用合併檔案,並使用記憶體中的檔案排序操作對記憶體中的行進行排序。

如果排序列中的多行具有相同的值,伺服器可以自由地以任何順序返回這些行,而且根據總體執行計劃的不同可能會有不同的結果。換句話說,這些行的排序順序是不確定的,非排序列也是如此。

影響執行計劃的一個因素是LIMIT,因此帶LIMIT和不帶LIMIT的ORDER BY查詢可能返回不同順序的行。考慮下面這個查詢,它按category列排序,但對於id和rating列不確定:

  • mysql> SELECT * FROM ratings ORDER BY category;
    +----+----------+--------+
    | id | category | rating |
    +----+----------+--------+
    |  1 |        1 |    4.5 |
    |  5 |        1 |    3.2 |
    |  3 |        2 |    3.7 |
    |  4 |        2 |    3.5 |
    |  6 |        2 |    3.5 |
    |  2 |        3 |    5.0 |
    |  7 |        3 |    2.7 |
    +----+----------+--------+

包含LIMIT可能會影響每個category值對應的行的順序。例如,下面是一個有效的查詢結果:

  • mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;
    +----+----------+--------+
    | id | category | rating |
    +----+----------+--------+
    |  1 |        1 |    4.5 |
    |  5 |        1 |    3.2 |
    |  4 |        2 |    3.5 |
    |  3 |        2 |    3.7 |
    |  6 |        2 |    3.5 |
    +----+----------+--------+

在每種情況下,行都按照排序列進行排序,這就是SQL標準所要求的全部內容。

如果確保有無LIMIT時的行順序相同很重要,可以在ORDER BY子句中加入其他列,以使順序確定。例如,如果id值是惟一的,可以通過如下排序使給定category值的行以id順序顯示:

mysql> SELECT * FROM ratings ORDER BY category, id;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
|  2 |        3 |    5.0 |
|  7 |        3 |    2.7 |
+----+----------+--------+

mysql> SELECT * FROM ratings ORDER BY category, id LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
+----+----------+--------+

PS:由於水平有限,譯文中難免會存在謬誤,歡迎批評指正。