MySQL sfalsa infinite righe


114

Vorrei costruire una query che visualizzi tutti i risultati in una tabella, ma è sfalsata di 5 dall'inizio della tabella. Per quanto ne so, MySQL LIMITrichiede un limite oltre che un offset. C'è un modo per fare questo?


1
Questa è una domanda del tutto valida, ma mi chiedo se cosa sarebbe meglio è prendere tutto e ignorare i primi record a livello di programmazione. Dato l'orrore di quella che sembra essere la risposta migliore (limite 5, 18446744073709551615), preferirei fortemente aggirare i limiti di LIMIT di MySQL.
cesoide

3
@cesoid cosa succede se vuoi limit 5000, 18446744073709551615. Non recupererai altre 5000 righe solo perché il tuo codice abbia un bell'aspetto.
elipoultorak

@ user3576887 Penso che tu abbia ragione, stavo solo considerando la domanda sopra partendo dal presupposto che 5 fosse l'unico requisito, piuttosto che una quantità variabile che potrebbe essere molto più grande (e piuttosto che risolvere il problema di qualcun altro).
cesoid

Suggerisco che questo sia un compito così raro che la bruttezza della soluzione possa essere accettata.
Rick James

Risposte:


151

Dal manuale MySQL su LIMIT :

Per recuperare tutte le righe da un certo offset fino alla fine del set di risultati, è possibile utilizzare un numero elevato per il secondo parametro. Questa istruzione recupera tutte le righe dalla 96a riga all'ultima:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
Terribile! Sono venuto qui sperando che MySQL rendesse la clausola Limit opzionale, così com'è, ma anche con un offset fornito ... ma no! Ho visto questo 18446744073709551615 sparso in tutto il codice e stavo incolpando i programmatori pigri, ma è una caratteristica del design!
Petruza

8
risposta orribile, ma è ufficiale di MySQL Doc. Cosa posso dire @ _ @
GusDeCooL

21
18446744073709551615 è 2 ^ 64-1 per coloro che se lo stavano chiedendo. Potresti voler fare attenzione perché non sarai in grado di memorizzare questo valore in un numero intero a 32 bit. Devi assicurarti di memorizzarlo come stringa per garantire la compatibilità.
AlicanC

13
Terribile! devono diventare più eleganti di così ... Limit -1o Limit Nullsembrano abbastanza ragionevoli! o almeno Limit dovrebbe accettare una sottoquery comeselect * from table limit (select count(*) from table)
vulcan raven

19
usa php 'PHP_INT_MAX' per evitare effetti di overflow.
Karl Adler

24

Come hai detto, è richiesto LIMIT, quindi devi utilizzare il limite più grande possibile, che è 18446744073709551615 (massimo di BIGINT non firmato)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
Wow, è questa la soluzione ufficiale del team MySQL?
Antony

12

Come notato in altre risposte, MySQL suggerisce di utilizzare 18446744073709551615 come numero di record nel limite, ma considera questo: cosa faresti se recuperassi 18.446.744.073.709.551.615 record? In effetti, cosa faresti se avessi 1.000.000.000 di record?

Forse vuoi più di un miliardo di record, ma il mio punto è che c'è un limite al numero che vuoi , ed è inferiore a 18 quintilioni. Per motivi di stabilità, ottimizzazione e possibilmente usabilità, suggerirei di porre un limite significativo alla query. Ciò ridurrebbe anche la confusione per chiunque non abbia mai visto quel numero dall'aspetto magico e avrebbe il vantaggio aggiuntivo di comunicare almeno quanti record sei disposto a gestire contemporaneamente.

Se davvero devi ottenere tutti i 18 quintilioni di record dal tuo database, forse quello che vuoi veramente è prenderli in incrementi di 100 milioni e loop 184 miliardi di volte.


Hai ragione, ma lasciare questa decisione allo sviluppatore non è una buona scelta
amd

@amd Potresti spiegarlo un po 'di più? Non so cosa stai cercando di dire.
cesoid

1
@cesoid Penso che stia dicendo che gli sviluppatori non dovrebbero essere quelli a scegliere arbitrariamente la logica di business, con cui sono d'accordo, ma solo fino a un certo punto. Supponiamo che tu stia restituendo un elenco di ordini a un cliente. È perfettamente ragionevole non restituire mai più di, diciamo, un milione alla volta, ma limitare a 100 potrebbe creare confusione.
Autumn Leonard

@amd Non sto dicendo che lo sviluppatore dovrebbe modificare il comportamento dell'app per evitare di utilizzare 18446744073709551615. Sto dicendo che dovrebbe considerare se l'uso di quel numero ha senso come parte dell'implementazione di qualsiasi cosa sia il client o il progettista dell'interfaccia ha richiesto, e che è molto improbabile che sia la giusta implementazione per qualsiasi cosa. La decisione di utilizzare MySQL è stata probabilmente già presa dallo sviluppatore senza chiedere se ci sarebbero stati più di 18 quintilioni di qualcosa.
cesoid

5

Un altro approccio potrebbe essere quello di selezionare una colonna autoimcrementata e quindi filtrarla utilizzando HAVING.

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

Ma probabilmente mi atterrei all'approccio del limite alto.


grazie, e mi chiedo come posso inserire tale query nell'istruzione PHP! $sql = 'SET @a :=0 SELECT .....';
Voglio

2

Come altri menzionati, dal manuale MySQL. Per ottenere ciò, puoi utilizzare il valore massimo di un big int senza segno, ovvero questo numero orribile (18446744073709551615). Ma per renderlo un po 'meno disordinato puoi usare l'operatore bit per bit tilde "~".

  LIMIT 95, ~0

funziona come una negazione bit per bit. Il risultato di "~ 0" è 18446744073709551615.


1
Non funziona in MariaDB 10.3 :( Ho provato sia LIMIT 5, ~0e LIMIT ~0 OFFSET 5. Questa è una funzionalità di MySQL 8.0?
jurchiks

1
Questa non è una cosa in MySQL 5.7 - sintassi non valida.
Jonny Nott,

0

Proprio oggi stavo leggendo il modo migliore per ottenere enormi quantità di dati (più di un milione di righe) da una tabella mysql. Un modo è, come suggerito, usare LIMIT x,ydov'è xl'offset e yl'ultima riga che vuoi restituire. Tuttavia, come ho scoperto, non è il modo più efficiente per farlo. Se hai una colonna di incremento automatico, puoi usare altrettanto facilmente SELECTun'istruzione con una WHEREclausola che dice da quale record desideri iniziare.

Per esempio, SELECT * FROM table_name WHERE id > x;

Sembra che mysql ottenga tutti i risultati quando lo usi LIMITe poi ti mostri solo i record che si adattano all'offset: non il massimo per le prestazioni.

Fonte: risposta a questa domanda MySQL Forums . Prendi nota, la domanda ha circa 6 anni.


13
Questo darà risultati errati se hai mai cancellato un record. Questo metodo è particolarmente pericoloso, perché funziona la maggior parte del tempo e fallisce silenziosamente quando non lo fa.
ottobre

0

Puoi utilizzare un'istruzione MySQL con 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;

Testato in MySQL 5.5.44. In questo modo possiamo evitare l'inserimento del numero 18446744073709551615.

nota: la transazione fa in modo che la variabile @rows sia in accordo con la tabella considerata nell'esecuzione dell'istruzione.


come ha affermato @amd: "selezionare il conteggio (*) su una tabella con 7
milioni di

-1

So che questo è vecchio ma non ho visto una risposta simile, quindi questa è la soluzione che userei.

Per prima cosa, eseguo una query di conteggio sulla tabella per vedere quanti record esistono. Questa query è veloce e normalmente il tempo di esecuzione è trascurabile. Qualcosa di simile a:

SELECT COUNT(*) FROM table_name;

Quindi creerei la mia query utilizzando il risultato ottenuto da count come limite (poiché questo è il numero massimo di righe che la tabella potrebbe eventualmente restituire). Qualcosa di simile a:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

O forse qualcosa di simile:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Ovviamente, se necessario, puoi sottrarre desiderato_offset da count_result per ottenere un valore effettivo e preciso da fornire come limite. Il passaggio del valore "18446744073709551610" non ha senso se posso effettivamente determinare un limite appropriato da fornire.


2
select count (*) su una tabella con 7 milioni di record richiede circa 17 secondi
e

-7
WHERE .... AND id > <YOUROFFSET>

id può essere qualsiasi colonna numerica autoincrementata o univoca che hai ...


7
Cattiva idea. Darà l'offset errato se hai mai cancellato una riga.
ottobre
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.