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:由于水平有限,译文中难免会存在谬误,欢迎批评指正。

猜你喜欢

转载自blog.csdn.net/qq_41080850/article/details/85634034