【问题标题】:How does MySQL process ORDER BY and LIMIT in a query?MySQL如何处理查询中的ORDER BY和LIMIT?
【发布时间】:2020-12-17 16:52:07
【问题描述】:

我有一个看起来像这样的查询:

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

ORDER BY 是如何工作的?它会排序所有记录,然后获取前 20 条记录,还是获取 20 条记录并按 publish_date 字段排序?

如果是最后一篇,你不能保证真的得到最新的 20 篇文章。

【问题讨论】:

  • 请注意,如果某些 publish_dates 相等,则按它们排序不会给出确定的结果,这意味着如果您使用 LIMIT 进行分页,您最终可能会在不同页面上获得相同的项目!
  • 注意你应用这些的顺序。如果你先做 LIMIT,然后做 ORDER BY,它会抛出一个错误。 ORDER BY 必须在查询中排在第一位。

标签: mysql sql sql-order-by sql-limit


【解决方案1】:

它将首先排序,然后获取前 20 个。数据库还将处理 ORDER BY 之前的 WHERE 子句中的任何内容。

【讨论】:

  • 所以时间是一样的?
  • 错误的! LIMIT打破ORDER BY。使用 LIMITORDER BY 返回错误的结果。 LIMIT 以某种方式重新排序ORDER BY 返回的结果集
  • @Green,你错了。阅读此解释:dev.mysql.com/doc/refman/5.7/en/limit-optimization.html 当 ORDER BY 列被索引时,当该列中有超过 1 个具有相同值的记录时,它可能会以与没有 LIMIT 时不同的顺序返回记录。
  • 此类问题的一个快速解决方案是通过最好具有唯一值来添加更多列以进行排序,以便当多行的第一个 order-by-column 值相同时,数据库获得一致的行排序规则。
【解决方案2】:

LIMIT 子句可用于限制 SELECT 语句返回的行数。 LIMIT 接受一个或两个数字参数,它们必须都是非负整数常量(使用准备语句时除外)。

有两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。初始行的偏移量为 0(不是 1):

SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

要检索从某个偏移量到结果集末尾的所有行,您可以为第二个参数使用一些较大的数字。此语句检索从第 96 行到最后一行的所有行:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

使用一个参数,该值指定从结果集开头返回的行数:

SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows

也就是说,LIMIT row_count 相当于 LIMIT 0, row_count。

所有详细信息:http://dev.mysql.com/doc/refman/5.0/en/select.html

【讨论】:

  • 它不是检索第 5-14 行吗?
  • @adonis 不,不是。该示例来自MySQL Documentation
  • 数字 5 是第 6 行。忽略 5 行(0 到 4)。
  • 但是在没有 ORDER BY 的情况下使用 LIMIT 可能会产生不一致的结果!不幸的是,必须在应用 LIMIT 之前对整个结果集进行排序,否则 DBMS 可以随意对结果进行任意排序,然后对该结果集进行 OFFSET 和 LIMIT。我读到这可能是由于 DBMS 选择了一个基于 OFFSET 和 LIMIT 的备用查询计划,因此是任意顺序。
  • 问题是询问限制和订购依据。但是答案与这个问题完全无关
【解决方案3】:

正如@James 所说,它将对所有记录进行排序,然后获取前 20 行。

如此一来,您将保证获得最先发表的20篇文章,较新的文章将不再显示。

你的情况,我建议你把desc加到order by publish_date上,如果你想要最新的文章,那么最新的文章会排在第一位。

如果你需要保持结果按升序排列,并且仍然只想要 10 篇最新的文章,你可以让 mysql 对你的结果进行两次排序。

下面的查询将对结果进行降序排序并将结果限制为 10(即括号内的查询)。还是会降序排列,我们不满足,再让mysql重新排序一次。现在我们在最后一行有最新的结果。

select t.article 
from 
    (select article, publish_date 
     from table1
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

如果您需要所有列,可以这样做:

select t.* 
from 
    (select * 
     from table1  
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

当我手动编写查询来检查数据库中的各种内容时,我会使用这种技术。我没有在生产环境中使用它,但现在当我对它进行基准测试时,额外的排序不会影响性能。

【讨论】:

  • 您的额外排序实际上不会对性能产生任何可衡量的影响,因为它仅限于 10 行/项目:-)。一般来说,对内存表(子选择正在生成)进行排序非常快并且几乎无法测量,除非您有数百万行或者 DBMS 正在将结果集分页到磁盘,因为它不适合内存(在这种情况下根据 DBMS,它也可以中止查询)。
【解决方案4】:

您可以在order by末尾添加[asc]或[desc]以获得最早或最新的记录

例如,这将首先为您提供最新记录

ORDER BY stamp DESC

ORDER BY之后附加LIMIT子句

【讨论】:

  • 欢迎来到计算器。我想你可能误解了这个问题。我相信他们是在询问操​​作顺序而不是“如何排序”。 (但这没有实际意义,因为问题已经在前一段时间得到了回答;)
【解决方案5】:

如果有合适的索引,在本例中是在 publish_date 字段上,那么 MySQL 不需要扫描整个索引来获取请求的 20 条记录——这 20 条记录将在索引的开头找到。但如果没有合适的索引,则需要对表进行全扫描。

有一个 MySQL Performance Blog article 从 2009 年开始。

【讨论】:

    【解决方案6】:

    您可以使用此代码 SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 其中 0 是记录的起始限制 & 10 记录数

    【讨论】:

    • 不,那不是必需的. LIMIT 10LIMIT 0,10 的简写。
    • 是的,LIMIT 0,10 不需要,但您可以像这样要求 Limit 10,20
    【解决方案7】:

    LIMIT 通常作为最后一个操作应用,因此会先对结果进行排序,然后限制为 20。实际上,只要找到前 20 个排序结果,排序就会停止。

    【讨论】:

    • 你的第二句话违背了你的第一句话。当找到前 20 个结果时排序不能停止,因为正如您所说,排序将在返回结果之前完成。 MySQL 只有在排序完成后才能知道前 20 个结果是什么。
    • @Tom,如果按索引列排序,实际上可以。这里有说明:dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
    • @Tom:与排序所有内容并获取前 k 行相比,您可以更有效地找到前 k 行。想想看。找到最小值 (k=1) 也不需要对所有行进行排序然后取第一行,而是可以在 O(n) 的时间内完成。对于前 k 行,这在时间 O(n + k * log k) 中是可能的,这就是数据库的工作方式。有关可能的算法列表,请参阅geeksforgeeks.org/k-largestor-smallest-elements-in-an-array
    【解决方案8】:

    可以简化为:

    SELECT article FROM table1 ORDER BY publish_date DESC FETCH FIRST 20 ROWS ONLY;

    您还可以在 ORDER BY 中添加许多参数,这些参数只是逗号分隔,例如:ORDER BY publish_date, tab2, tab3 DESC 等...

    【讨论】:

      猜你喜欢
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-09
      • 2020-11-19
      • 1970-01-01
      相关资源
      最近更新 更多