MySQL desloca linhas infinitas

114

Eu gostaria de construir uma consulta que exibe todos os resultados em uma tabela, mas é compensada por 5 desde o início da tabela. Pelo que eu posso dizer, o MySQL LIMITrequer um limite, bem como um deslocamento. Há alguma maneira de fazer isso?

Stillinbeta
fonte
1
Esta é uma pergunta totalmente válida, mas eu me pergunto se o que seria melhor seria pegar tudo e desconsiderar os primeiros registros programaticamente. Dado o horror do que parece ser a melhor resposta (limite 5, 18446744073709551615), eu seria a favor de contornar as limitações do LIMIT do MySQL.
cesóide
3
@cesoid e se você quiser limit 5000, 18446744073709551615. Você não vai buscar 5000 linhas extras apenas para que seu código fique bonito.
elipoultorak
@ user3576887 Acho que você está certo, eu estava apenas considerando a questão acima com a suposição de que 5 era o único requisito, em vez de uma quantidade variável que pode ser muito maior (e em vez de resolver o problema de outra pessoa).
cesoid
Sugiro que esta é uma tarefa tão rara que a feiura da solução pode ser aceita.
Rick James

Respostas:

151

Do manual do MySQL em LIMIT :

Para recuperar todas as linhas de um certo 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 96ª à última:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;
Greg
fonte
105
Horrível! Vim aqui esperando que o MySQL tornasse a cláusula Limit opcional, mas também com um deslocamento fornecido ... mas não! Eu vi isso 18446744073709551615 espalhado por todo o código e estava culpando os programadores preguiçosos, mas é um recurso de design!
Petruza
8
resposta horrível, mas isso é oficial do MySQL Doc. O que posso dizer @ _ @
GusDeCooL
21
18446744073709551615 é 2 ^ 64-1 para aqueles que estavam se perguntando. Você pode querer ficar atento porque não será capaz de armazenar esse valor em um inteiro de 32 bits. Você deve certificar-se de armazená-lo como uma string para garantir a compatibilidade.
AlicanC
13
Terrível! eles precisam ficar mais elegantes do que isso ... Limit -1ou Limit Nullparece bem razoável! ou pelo menos o Limit deve aceitar uma subconsulta comoselect * from table limit (select count(*) from table)
vulcan raven
19
use php 'PHP_INT_MAX' para evitar efeitos de estouro.
Karl Adler,
24

Como você mencionou, LIMIT é obrigatório, então você precisa usar o maior limite possível, que é 18446744073709551615 (máximo de BIGINT sem sinal)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5
Czimi
fonte
33
Uau, essa é a solução oficial da equipe MySQL?
Antônio
12

Conforme observado em outras respostas, o MySQL sugere usar 18446744073709551615 como o número de registros no limite, mas considere o seguinte: O que você faria se obtivesse 18.446.744.073.709.551.615 registros de volta? Na verdade, o que você faria se tivesse 1.000.000.000 de registros?

Talvez você queira mais de um bilhão de registros, mas meu ponto é que existe um limite para o número que você deseja , e é menos de 18 quintilhões. Por uma questão de estabilidade, otimização e possivelmente usabilidade, sugiro colocar algum limite significativo na consulta. Isso também reduziria a confusão para quem nunca viu aquele número de aparência mágica e teria o benefício adicional de comunicar pelo menos quantos registros você está disposto a lidar de uma vez.

Se você realmente precisa obter todos os 18 quintilhões de registros de seu banco de dados, talvez o que você realmente queira é pegá-los em incrementos de 100 milhões e fazer um loop de 184 bilhões de vezes.

cesóide
fonte
Você está certo, mas manter esta decisão para o desenvolvedor não é uma boa escolha
amd
@amd Você poderia explicar um pouco mais? Eu não sei o que você está tentando dizer.
cesóide
1
@cesoid Acho que ele está dizendo que os devs não deveriam ser os únicos a escolher arbitrariamente a lógica de negócios, com a qual concordo, mas apenas até certo ponto. Digamos que você esteja devolvendo uma lista de pedidos a um cliente. É perfeitamente razoável nunca retornar mais do que, digamos, um milhão de cada vez, mas limitar a 100 pode causar confusão.
Autumn Leonard
@amd Não estou dizendo que o desenvolvedor deve mudar o comportamento do aplicativo para evitar o uso de 18446744073709551615. Estou dizendo que eles devem considerar se usar esse número faz sentido como parte da implementação de qualquer que seja o cliente ou designer de interface solicitou e que é muito improvável que seja a implementação certa para qualquer coisa. A decisão de usar o MySQL provavelmente já foi feita pelo desenvolvedor sem perguntar se haveria mais de 18 quintilhões de algo.
cesóide de
5

Outra abordagem seria selecionar uma coluna autoimcrementada e filtrá-la usando HAVING.

SET @a := 0; 
select @a:=@a + 1 AS counter, table.* FROM table 
HAVING counter > 4

Mas provavelmente continuaria com a abordagem de limite alto.

jishi
fonte
obrigado, e eu me pergunto como posso colocar essa consulta na instrução PHP! quero dizer assim$sql = 'SET @a :=0 SELECT .....';
Reham Fahmy
2

Como outros mencionaram, do manual do MySQL. Para conseguir isso, você pode usar o valor máximo de um grande int sem sinal, que é este número terrível (18446744073709551615). Mas para torná-lo um pouco menos confuso, você pode usar o operador til "~" bit a bit.

  LIMIT 95, ~0

funciona como uma negação bit a bit. O resultado de "~ 0" é 18446744073709551615.

Bruno.S
fonte
1
Não funciona no MariaDB 10.3 :( Tentei os dois LIMIT 5, ~0e LIMIT ~0 OFFSET 5. Este é um recurso do MySQL 8.0?
jurchiks
1
Isso não é uma coisa no MySQL 5.7 - sintaxe inválida.
Jonny Nott
0

Ainda hoje eu estava lendo sobre a melhor maneira de obter grandes quantidades de dados (mais de um milhão de linhas) de uma tabela mysql. Uma maneira é, como sugerido, usar LIMIT x,yonde xestá o deslocamento e ya última linha que você deseja retornar. Porém, como descobri, não é a maneira mais eficiente de fazer isso. Se você tem uma coluna de incremento automático, pode facilmente usar uma SELECTinstrução com uma WHEREcláusula dizendo de qual registro você gostaria de começar.

Por exemplo, SELECT * FROM table_name WHERE id > x;

Parece que o mysql obtém todos os resultados quando você usa LIMITe só mostra os registros que cabem no deslocamento: não é o melhor para desempenho.

Fonte: Resposta a esta pergunta MySQL Forums . Só preste atenção, a pergunta tem cerca de 6 anos.

alimentado
fonte
13
Isso dará resultados incorretos se você já excluiu um registro. Este método é especialmente perigoso porque funciona na maioria das vezes e falha silenciosamente quando não funciona.
outubro de
0

Você pode usar uma instrução MySQL com LIMIT:

START TRANSACTION;
SET @my_offset = 5;
SET @rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING @rows, @my_offset;
COMMIT;

Testado em MySQL 5.5.44. Assim, podemos evitar a inserção do número 18446744073709551615.

nota: a transação garante que a variável @rows esteja de acordo com a tabela considerada na execução do demonstrativo.

sissi_luaty
fonte
como @amd afirmou: "selecionar contagem (*) em uma mesa com 7 milhões de registros leva cerca de 17s"
Rodrirokr
-1

Eu sei que isso é antigo, mas não vi uma resposta semelhante, então esta é a solução que eu usaria.

Primeiro, eu executaria uma consulta de contagem na tabela para ver quantos registros existem. Esta consulta é rápida e normalmente o tempo de execução é insignificante. Algo como:

SELECT COUNT(*) FROM table_name;

Então, eu construiria minha consulta usando o resultado que obtive da contagem como meu limite (já que esse é o número máximo de linhas que a tabela poderia retornar). Algo como:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Ou possivelmente algo como:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Claro, se necessário, você pode subtrair desejado_offset de count_result para obter um valor real e preciso para fornecer como limite. Passar o valor "18446744073709551610" simplesmente não faz sentido se eu puder determinar um limite apropriado a ser fornecido.

Baron Von Sparklefarts
fonte
2
selecionar contagem (*) em uma tabela com registros 7M leva cerca de 17s
amd
-7
WHERE .... AND id > <YOUROFFSET>

id pode ser qualquer coluna numérica única ou autoincrementada que você tem ...

user3131125
fonte
7
Péssima ideia. Ele dará o deslocamento incorreto se você já excluiu uma linha.
outubro de