MySQL versetzt unendliche Zeilen

114

Ich möchte eine Abfrage erstellen, die alle Ergebnisse in einer Tabelle anzeigt, aber vom Anfang der Tabelle um 5 versetzt ist. Soweit ich das beurteilen kann, LIMITerfordert MySQL sowohl ein Limit als auch einen Offset. Gibt es eine Möglichkeit, dies zu tun?

stillinbeta
quelle
1
Dies ist eine absolut gültige Frage, aber ich frage mich, ob es besser wäre, alles zu erfassen und die ersten paar Datensätze programmgesteuert zu ignorieren. Angesichts des Schreckens über die scheinbar beste Antwort (Limit 5, 18446744073709551615) würde ich es sehr bevorzugen, die Einschränkungen von MySQLs LIMIT zu umgehen.
Cesoid
3
@cesoid was ist wenn du willst limit 5000, 18446744073709551615. Sie werden keine zusätzlichen 5000 Zeilen abrufen, nur damit Ihr Code hübsch aussieht.
Elipoultorak
@ user3576887 Ich denke, Sie haben Recht, ich habe nur die obige Frage mit der Annahme betrachtet, dass 5 die einzige Anforderung ist, und nicht eine unterschiedliche Menge, die viel größer sein könnte (und anstatt das Problem eines anderen zu lösen).
Cesoid
Ich schlage vor, dass dies eine so seltene Aufgabe ist, dass die Hässlichkeit der Lösung akzeptiert werden kann.
Rick James

Antworten:

151

Aus dem MySQL-Handbuch zu LIMIT :

Um alle Zeilen von einem bestimmten Versatz bis zum Ende der Ergebnismenge abzurufen, können Sie für den zweiten Parameter eine große Zahl verwenden. Diese Anweisung ruft alle Zeilen von der 96. bis zur letzten Zeile ab:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;
Greg
quelle
104
Schrecklich! Ich bin hierher gekommen in der Hoffnung, dass MySQL die Limit-Klausel so wie sie ist optional gemacht hat, aber auch mit einem Offset ... aber nein! Ich habe gesehen, dass diese 18446744073709551615 über den gesamten Code verteilt ist, und ich habe faulen Programmierern die Schuld gegeben, aber es ist ein Designmerkmal!
Petruza
8
schreckliche Antwort, aber das ist offiziell von MySQL Doc. Was ich sagen kann @ _ @
GusDeCooL
21
18446744073709551615 ist 2 ^ 64-1 für diejenigen, die sich wunderten. Möglicherweise möchten Sie aufpassen, da Sie diesen Wert nicht in einer 32-Bit-Ganzzahl speichern können. Sie müssen sicherstellen, dass Sie dies als Zeichenfolge speichern, um die Kompatibilität sicherzustellen.
AlicanC
13
Furchtbar! sie müssen eleganter werden ... Limit -1oder sehen Limit Nullziemlich vernünftig aus! oder mindestens Limit sollte eine Unterabfrage wieselect * from table limit (select count(*) from table)
Vulkanrabe
19
Verwenden Sie PHP 'PHP_INT_MAX', um Überlaufeffekte zu vermeiden.
Karl Adler
24

Wie Sie bereits erwähnt haben, ist LIMIT erforderlich, daher müssen Sie das größtmögliche Limit verwenden, nämlich 18446744073709551615 (maximal BIGINT ohne Vorzeichen).

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5
Czimi
quelle
33
Wow, ist das die offizielle Lösung des MySQL-Teams?
Antonius
12

Wie in anderen Antworten erwähnt, schlägt MySQL vor, 18446744073709551615 als Anzahl der Datensätze im Limit zu verwenden. Beachten Sie jedoch Folgendes: Was würden Sie tun, wenn Sie 18.446.744.073.709.551.615 Datensätze zurückerhalten würden? Was würden Sie tun, wenn Sie 1.000.000.000 Datensätze hätten?

Vielleicht möchten Sie mehr als eine Milliarde Datensätze, aber mein Punkt ist, dass die Anzahl der gewünschten Datensätze begrenzt ist und weniger als 18 Billionen beträgt. Aus Gründen der Stabilität, Optimierung und möglicherweise Benutzerfreundlichkeit würde ich vorschlagen, die Abfrage sinnvoll einzuschränken. Dies würde auch die Verwirrung für jeden verringern, der diese magisch aussehende Zahl noch nie gesehen hat, und den zusätzlichen Vorteil haben, mindestens zu kommunizieren, wie viele Datensätze Sie gleichzeitig verarbeiten möchten.

Wenn Sie wirklich alle 18 Billionen Datensätze aus Ihrer Datenbank abrufen müssen, möchten Sie sie möglicherweise in Schritten von 100 Millionen abrufen und 184 Milliarden Mal durchlaufen.

cesoid
quelle
Sie haben Recht, aber diese Entscheidung in den Entwickler zu halten , ist keine gute Wahl
amd
@amd Könntest du das etwas näher erläutern? Ich weiß nicht, was du sagen willst.
Cesoid
1
@cesoid Ich denke, er sagt, dass Entwickler nicht diejenigen sein sollten, die willkürlich die Geschäftslogik wählen, der ich zustimme, sondern nur bis zu einem gewissen Punkt. Angenommen, Sie senden eine Liste mit Bestellungen an einen Kunden zurück. Es ist durchaus vernünftig, niemals mehr als beispielsweise eine Million auf einmal zurückzugeben, aber eine Beschränkung auf 100 kann Verwirrung stiften.
Herbst Leonard
@amd Ich sage nicht, dass der Entwickler das Verhalten der App ändern sollte, um die Verwendung von 18446744073709551615 zu vermeiden. Ich sage, dass er überlegen sollte, ob die Verwendung dieser Nummer im Rahmen der Implementierung des Client- oder Interface-Designers sinnvoll ist hat beantragt, und dass es sehr unwahrscheinlich ist, dass die richtige Implementierung für irgendetwas ist. Die Entscheidung für MySQL wurde wahrscheinlich bereits vom Entwickler getroffen, ohne zu fragen, ob es mehr als 18 Billionen von etwas geben würde.
Cesoid
5

Ein anderer Ansatz wäre, eine automatisch inkrementierte Spalte auszuwählen und sie dann mit HAVING zu filtern.

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

Aber ich würde mich wahrscheinlich an den High-Limit-Ansatz halten.

Jishi
quelle
Vielen Dank, und ich frage mich, wie ich eine solche Abfrage in PHP-Anweisung setzen kann! Ich meine so$sql = 'SET @a :=0 SELECT .....';
Reham Fahmy
1

Wie bereits erwähnt, aus dem MySQL-Handbuch. Um dies zu erreichen, können Sie den Maximalwert eines vorzeichenlosen Big Int verwenden, dh diese schreckliche Zahl (18446744073709551615). Aber um es ein bisschen weniger chaotisch zu machen, können Sie den bitweisen Operator "~" verwenden.

  LIMIT 95, ~0

es funktioniert als bitweise Negation. Das Ergebnis von "~ 0" ist 18446744073709551615.

Bruno.S
quelle
1
Funktioniert nicht in MariaDB 10.3 :( Ich habe versucht , beide LIMIT 5, ~0und LIMIT ~0 OFFSET 5Ist das eine MySQL 8.0 - Funktion.?
jurchiks
1
Dies ist in MySQL 5.7 keine Sache - ungültige Syntax.
Jonny Nott
0

Erst heute habe ich gelesen, wie man am besten große Datenmengen (mehr als eine Million Zeilen) aus einer MySQL-Tabelle abruft. Eine Möglichkeit ist, wie vorgeschlagen, mit LIMIT x,ydenen xder Offset und ydie letzte Zeile zurückgegeben werden soll. Wie ich jedoch herausgefunden habe, ist dies nicht der effizienteste Weg, dies zu tun. Wenn Sie eine Autoincrement-Spalte haben, können Sie genauso einfach eine SELECTAnweisung mit einer WHEREKlausel verwenden, die angibt, von welchem ​​Datensatz Sie beginnen möchten.

Beispielsweise, SELECT * FROM table_name WHERE id > x;

Es scheint, dass MySQL alle Ergebnisse erhält, wenn Sie es verwenden, LIMITund Ihnen dann nur die Datensätze anzeigt, die in den Offset passen: nicht die beste Leistung.

Quelle: Antwort auf diese Frage MySQL-Foren . Beachten Sie nur, dass die Frage ungefähr 6 Jahre alt ist.

gefüttert
quelle
13
Dies führt zu falschen Ergebnissen, wenn Sie jemals einen Datensatz gelöscht haben. Diese Methode ist besonders gefährlich, da sie die meiste Zeit funktioniert und stillschweigend fehlschlägt, wenn dies nicht der Fall ist.
Oktober
0

Sie können eine MySQL-Anweisung mit LIMIT verwenden:

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;

Getestet in MySQL 5.5.44. Somit können wir das Einfügen der Nummer 18446744073709551615 vermeiden.

Hinweis: Die Transaktion stellt sicher, dass die Variable @rows mit der Tabelle übereinstimmt, die bei der Ausführung der Anweisung berücksichtigt wird.

sissi_luaty
quelle
wie @amd sagte: "Die Auswahl der Anzahl (*) für eine Tabelle mit
7 Millionen
-1

Ich weiß, dass dies alt ist, aber ich habe keine ähnliche Antwort gesehen, daher ist dies die Lösung, die ich verwenden würde.

Zuerst würde ich eine Zählabfrage für die Tabelle ausführen, um zu sehen, wie viele Datensätze vorhanden sind. Diese Abfrage ist schnell und normalerweise ist die Ausführungszeit vernachlässigbar. Etwas wie:

SELECT COUNT(*) FROM table_name;

Dann würde ich meine Abfrage mit dem Ergebnis erstellen, das ich von count als mein Limit erhalten habe (da dies die maximale Anzahl von Zeilen ist, die die Tabelle möglicherweise zurückgeben könnte). Etwas wie:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Oder vielleicht so etwas wie:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Bei Bedarf können Sie natürlich den gewünschten Versatz von count_result abziehen, um einen tatsächlichen, genauen Wert zu erhalten, der als Grenzwert angegeben werden soll. Das Übergeben des Werts "18446744073709551610" ist nur dann sinnvoll, wenn ich tatsächlich einen geeigneten Grenzwert festlegen kann.

Baron Von Sparklefarts
quelle
2
Die Auswahl der Anzahl (*) für eine Tabelle mit 7 Millionen Datensätzen dauert ungefähr 17 Sekunden
und
-7
WHERE .... AND id > <YOUROFFSET>

id kann jede automatisch inkrementierte oder eindeutige numerische Spalte sein, die Sie haben ...

user3131125
quelle
7
Schlechte Idee. Es wird der falsche Versatz angezeigt, wenn Sie jemals eine Zeile gelöscht haben.
Oktober