MySQL如何处理查询中的ORDER BY和LIMIT?


250

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

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

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

如果是最后一篇,则不能保证您会真正获得最新的20篇文章。


6
请注意,如果某些publish_dates相等,则按它们排序不会给出确定的结果,这意味着,如果LIMIT用于分页,则最终可能会在不同页面上得到相同的项!
Konrad Morawski

Answers:


244

它将先排序,然后得到前20。数据库还将处理WHERE子句中的所有内容ORDER BY


1
那么时间是一样的吗?
Yasar Arafath

7
错误!LIMIT休息ORDER BY。随着LIMIT一个ORDER BY返回错误的结果。LIMIT不知何故重新排序了由ORDER BY
Green(格林)

6
@格林,你错了。请阅读以下内容以获取解释:dev.mysql.com/doc/refman/5.7/en/limit-optimization.html当对ORDER BY列建立索引时,如果返回的记录更多,则返回记录的顺序可能与没有LIMIT的记录不同。该列中具有相同值的1个以上的记录。
yitwail

1
解决此类问题的一种快速解决方案是,通过最好具有唯一的值来增加一个列,以便当第一行的第一个列的值对于多行相同时,数据库获得一致的行排序规则。
rineez

37

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 K. Kakoulidis

@adonis不,不是。该示例来自MySQL文档
dcaswell,2013年

5号是第六行。5行(0到4)将被忽略。
Phil Perry

1
但是,在没有ORDER BY的情况下使用LIMIT可能会产生不一致的结果!不幸的是,必须在应用LIMIT之前对整个结果集进行排序,否则DBMS可以随意对结果进行任意排序,然后对该集合进行OFFSET和LIMIT。我已经读到这可能是由于DBMS基于OFFSET和LIMIT从而选择了任意顺序而选择了替代查询计划。
巴顿

4
问题是要求限制和订购。但是答案根本与这个问题无关
沉亮,2017年

9

就像@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;

当我手动编写查询以检查数据库中的各种内容时,会使用此技术。我没有在生产环境中使用它,但是现在当我在基准上对其进行标记时,多余的排序不会影响性能。


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

7

如果有合适的索引(在这种情况下是在publish_date字段上),则MySQL无需扫描整个索引即可获取请求的20条记录-在索引的开头将找到20条记录。但是,如果没有合适的索引,则需要对表进行全面扫描。

2009年有一篇MySQL Performance Blog文章


7

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

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

ORDER BY stamp DESC

在此LIMIT之后追加条款ORDER BY


3
欢迎来到stackoverflow。我认为您可能误解了这个问题。我相信他们是在问操作顺序,而不是“如何排序”。(但这是有争议的,因为问题已经在不久前得到了回答;)
Leigh 2012年

5

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


8
不,那不是必需的LIMIT 10是的简写LIMIT 0,10
劳伦斯·多尔

2
是的,不需要LIMIT 0,10,但您可以要求像这样的Limit 10,20
gaurangkathiriya 2014年

3

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


11
您的第二句话与您的第一句话背道而驰。找到前20个结果后,排序将无法停止,因为正如您所说,将在返回结果之前进行排序。MySQL只能知道排序完成后的前20个结果是什么。
汤姆(Tom)

@Tom实际上可以,如果按索引列进行排序。它在这里解释:dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail

-3

另外,LIMIT的语法根据数据库而有所不同,例如:

mysql -极限1、2

postgres -限制2偏移1

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.