Como o MySQL processa ORDER BY e LIMIT em uma consulta?


251

Eu tenho uma consulta que se parece com isso:

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

Como o ORDER BY funciona? Ele ordenará todos os registros e, em seguida, obterá os 20 primeiros ou obterá 20 registros e os solicitará pelo publish_datecampo?

Se for o último, não há garantia de obter os 20 artigos mais recentes.


6
Observe que, se alguns publish_dates são iguais, a ordenação por eles não fornece resultados determinados, o que significa que, se você usar LIMITpara paginação, poderá acabar recebendo os mesmos itens em páginas diferentes!
Konrad Morawski

Respostas:


244

Ele fará o pedido primeiro e, depois, o primeiro 20. Um banco de dados também processará qualquer coisa da WHEREcláusula anterior ORDER BY.


1
Então o tempo é o mesmo?
Yasar Arafath 28/03

7
Errado! LIMITintervalos ORDER BY. Com LIMITum ORDER BYresultado errado retorna. LIMITde alguma forma reordena o conjunto de resultados retornado porORDER BY
Green

6
@ Green, você está enganado. Leia isto para obter a explicação: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html Quando a coluna ORDER BY é indexada, ela pode retornar registros em uma ordem diferente daquela sem o LIMIT, quando houver mais de 1 registro com o mesmo valor nessa coluna.
precisa saber é

1
Uma solução rápida para esses problemas é adicionar mais uma coluna à ordem, tendo preferencialmente valores únicos, para que o banco de dados obtenha uma regra consistente para ordenar linhas quando o valor da primeira ordem por coluna for o mesmo para várias linhas.
Rineez # 15/17

37

A cláusula LIMIT pode ser usada para restringir o número de linhas retornadas pela instrução SELECT. LIMIT usa um ou dois argumentos numéricos, que devem ser constantes inteiras não-negativas (exceto ao usar instruções preparadas).

Com dois argumentos, o primeiro argumento especifica o deslocamento da primeira linha a retornar e o segundo especifica o número máximo de linhas a serem retornadas. O deslocamento da linha inicial é 0 (não 1):

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

Para recuperar todas as linhas de um determinado deslocamento até o final do conjunto de resultados, você pode usar um número grande para o segundo parâmetro. Esta instrução recupera todas as linhas da 96a linha até a última:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

Com um argumento, o valor especifica o número de linhas a serem retornadas desde o início do conjunto de resultados:

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

Em outras palavras, LIMIT número_de-linha é equivalente a LIMIT 0, número-de-linha.

Todos os detalhes em: http://dev.mysql.com/doc/refman/5.0/en/select.html


Não é recuperar linhas 5-14?
Adonis K. Kakoulidis

@ adonis Não, não é. O exemplo é direto da documentação
dcaswell 15/10/2013

O número 5 é a sexta linha. 5 linhas (0 a 4) são ignoradas.
Phil Perry

1
Mas usar LIMIT sem ORDER BY pode gerar resultados inconsistentes! Infelizmente, todo o conjunto de resultados deve ser solicitado antes que o LIMIT seja aplicado ou o DBMS esteja livre para ordenar arbitrariamente o resultado e, em seguida, OFFSET e LIMIT nesse conjunto. Eu li que isso pode ser devido ao DBMS selecionar um plano de consulta alternativo com base em OFFSET e LIMIT, portanto, na ordem arbitrária.
Barton

4
pergunta é fazer o limite e ordenar por. Mas a resposta não está relacionada a esta pergunta
Shen liang 3/17

9

Assim como @James diz, ele ordenará todos os registros e obterá as primeiras 20 linhas.

Sendo assim, você garante os 20 primeiros artigos publicados, os mais novos não serão exibidos.

Em sua situação, eu recomendo que você adicionar descpara order by publish_date, se quiser que os artigos mais recentes, em seguida, o mais novo artigo vai ser o primeiro.

Se você precisar manter o resultado em ordem crescente, e ainda desejar apenas os 10 artigos mais recentes, pode solicitar ao mysql que classifique o resultado duas vezes.

Esta consulta abaixo classificará o resultado decrescente e limitará o resultado a 10 (que é a consulta entre parênteses). Ele ainda será classificado em ordem decrescente, e não estamos satisfeitos com isso, então pedimos ao mysql para classificá-lo mais uma vez. Agora temos o resultado mais recente na última linha.

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

order by t.publish_date asc;

Se você precisar de todas as colunas, isso é feito da seguinte maneira:

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

order by t.publish_date asc;

Eu uso essa técnica quando escrevo manualmente consultas para examinar o banco de dados em busca de várias coisas. Eu não o usei em um ambiente de produção, mas agora, quando eu o marquei, a classificação extra não afeta o desempenho.


2
Sua classificação extra virtualmente não pode ter nenhum impacto mensurável no desempenho, uma vez que é limitada a apenas 10 linhas / itens :-). Em geral, a classificação de uma tabela na memória (que uma sub-seleção está produzindo) é muito rápida e mal mensurável, a menos que você tenha milhões de linhas ou o DBMS esteja paginando o conjunto de resultados no disco, pois não cabe na memória (nesse caso, dependendo do DBMS, ele também pode abortar a consulta).
Martin Kersten

7

Se houver um índice adequado, neste caso no publish_datecampo, o MySQL não precisará varrer o índice inteiro para obter os 20 registros solicitados - os 20 registros serão encontrados no início do índice. Mas se não houver um índice adequado, será necessária uma varredura completa da tabela.

Existe um artigo do MySQL Performance Blog de 2009 sobre isso.


7

Você pode adicionar [asc] ou [desc] no final do pedido para obter os registros mais antigos ou mais recentes

Por exemplo, isso fornecerá os registros mais recentes primeiro

ORDER BY stamp DESC

Anexe a LIMITcláusula apósORDER BY


3
Bem-vindo ao stackoverflow. Eu acho que você pode ter entendido mal a pergunta. Eu acredito que eles estavam perguntando sobre a ordem das operações, em vez de "como classificar". (Mas é discutível uma vez que a questão já foi respondida há um tempo atrás;)
Leigh

5

Você pode usar este código em SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 que 0 é um limite inicial de registro e 10 número de registro


8
Não, isso não é necessário . LIMIT 10é uma abreviação de LIMIT 0,10.
Lawrence Dol

2
sim, não é obrigatório para o LIMIT 0,10, mas você pode exigir o seguinte limite 10,20
gaurangkathiriya

3

LIMIT é normalmente aplicado como a última operação, portanto o resultado será classificado primeiro e depois limitado a 20. Na verdade, a classificação será interrompida assim que os primeiros 20 resultados classificados forem encontrados.


11
Sua segunda frase vai contra a sua primeira. A classificação não pode parar quando os 20 primeiros resultados são encontrados porque, como você disse, a classificação será feita antes que os resultados sejam retornados. O MySQL só pode saber quais são os primeiros 20 resultados após a classificação terminar.
27413 Tom

@ Tom, na verdade, pode, se ordenando por uma coluna indexada. É explicado aqui: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail

-3

Também a sintaxe de LIMIT é diferente de acordo com os bancos de dados, por exemplo:

mysql - LIMITE 1, 2

postgres - LIMITE 2 OFFSET 1

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.