Ich habe in letzter Zeit mit Redis und MongoDB experimentiert und es scheint, dass es häufig Fälle gibt, in denen Sie eine Reihe von IDs entweder in MongoDB oder in Redis speichern . Ich bleibe bei Redis für diese Frage, da ich nach dem MySQL IN- Operator frage .
Ich frage mich , wie performant ist es eine große Anzahl (300-3000) von zur Liste ids innerhalb des IN - Operator, die etwa wie folgt aussehen:
SELECT id, name, price
FROM products
WHERE id IN (1, 2, 3, 4, ...... 3000)
Stellen Sie sich etwas so Einfaches wie eine Produkt- und Kategorietabelle vor , die Sie normalerweise zusammenfügen, um die Produkte aus einer bestimmten Kategorie zu erhalten . Im obigen Beispiel können Sie sehen, dass category:4:product_ids
ich unter einer bestimmten Kategorie in Redis ( ) alle Produkt-IDs aus der Kategorie mit der ID 4 zurückgebe und sie in der obigen SELECT
Abfrage innerhalb des IN
Operators platziere.
Wie performant ist das?
Ist das eine "es kommt darauf an" Situation? Oder gibt es ein konkretes "das ist (un) akzeptabel" oder "schnell" oder "langsam" oder sollte ich ein hinzufügen LIMIT 25
, oder hilft das nicht?
SELECT id, name, price
FROM products
WHERE id IN (1, 2, 3, 4, ...... 3000)
LIMIT 25
Oder sollte ich das Array der von Redis zurückgegebenen Produkt-IDs kürzen, um es auf 25 zu beschränken, und nur 25 IDs zur Abfrage hinzufügen, anstatt 3000, und LIMIT
es innerhalb der Abfrage auf 25 hinzufügen ?
SELECT id, name, price
FROM products
WHERE id IN (1, 2, 3, 4, ...... 25)
Anregungen / Feedback wird sehr geschätzt!
quelle
id IN (1,2,3 ... 3000)
Leistung im Vergleich zur JOIN-Tabelle vonproducts_categories
. Oder haben Sie das gesagt?IN
Klausel durchführen (dies kann in einer sortierten Liste, wie Sie zeigen, je nach Algorithmus sogar linear sein) und dann eine lineare Schnittmenge / Suche .Antworten:
Wenn die
IN
Liste zu groß wird (für einen schlecht definierten Wert von "zu groß", der normalerweise im Bereich von 100 oder kleiner liegt), wird es im Allgemeinen effizienter, einen Join zu verwenden und bei Bedarf eine temporäre Tabelle zu erstellen die Zahlen zu halten.Wenn die Zahlen eine dichte Menge sind (keine Lücken - was die Beispieldaten nahe legen), können Sie es noch besser machen
WHERE id BETWEEN 300 AND 3000
.Vermutlich gibt es jedoch Lücken in der Menge. An diesem Punkt ist es möglicherweise besser, mit der Liste der gültigen Werte zu beginnen (es sei denn, die Anzahl der Lücken ist relativ gering. In diesem Fall könnten Sie Folgendes verwenden:
Oder was auch immer die Lücken sind.
quelle
AND id NOT BETWEEN XXX AND XXX
, funktioniert dies nicht und es ist besser, dies zu tun(x = 1 OR x = 2 OR x = 3 ... OR x = 99)
bleib bei dem Äquivalent, wie @David Fells schrieb.Ich habe einige Tests durchgeführt, und wie David Fells in seiner Antwort sagt , ist es ziemlich gut optimiert. Als Referenz habe ich eine InnoDB-Tabelle mit 1.000.000 Registern erstellt und mit dem Operator "IN" mit 500.000 Zufallszahlen eine Auswahl getroffen. Auf meinem MAC dauert dies nur 2,5 Sekunden. Die Auswahl nur der geraden Register dauert 0,5 Sekunden.
Das einzige Problem, das ich hatte, war, dass ich den
max_allowed_packet
Parameter aus dermy.cnf
Datei erhöhen musste . Wenn nicht, wird ein mysteriöser Fehler "MYSQL ist verschwunden" generiert.Hier ist der PHP-Code, mit dem ich den Test mache:
Und die Ergebnisse:
quelle
%
) mit einem Gleichheitsoperator (=
) anstelle von verwendetIN()
.Sie können eine temporäre Tabelle erstellen, in die Sie eine beliebige Anzahl von IDs eingeben und eine verschachtelte Abfrage ausführen können. Beispiel:
und wählen Sie:
quelle
IN
ist in Ordnung und gut optimiert. Stellen Sie sicher, dass Sie es in einem indizierten Feld verwenden und es Ihnen gut geht.Es ist funktional äquivalent zu:
Was den DB-Motor betrifft.
quelle
IN
verwendet Optimierungen für eine bessere Leistung.Die Verwendung
IN
mit einem großen Parametersatz für eine große Liste von Datensätzen ist in der Tat langsam.In dem Fall, den ich kürzlich gelöst habe, hatte ich zwei where-Klauseln, eine mit 2,50 Parametern und die andere mit 3.500 Parametern, die eine Tabelle mit 40 Millionen Datensätzen abfragten.
Meine Anfrage dauerte 5 Minuten mit dem Standard
WHERE IN
. Indem ich stattdessen eine Unterabfrage für die IN- Anweisung verwendete (die Parameter in eine eigene indizierte Tabelle einfügte ), wurde die Abfrage auf ZWEI Sekunden reduziert.Arbeitete meiner Erfahrung nach sowohl für MySQL als auch für Oracle.
quelle
Wenn Sie viele Werte für den
IN
Operator angeben, muss dieser zuerst sortiert werden, um Duplikate zu entfernen. Zumindest vermute ich das. Es wäre also nicht gut, zu viele Werte anzugeben, da das Sortieren N log N Zeit benötigt.Meine Erfahrung hat gezeigt, dass das Aufteilen der Wertemenge in kleinere Teilmengen und das Kombinieren der Ergebnisse aller Abfragen in der Anwendung die beste Leistung ergibt. Ich gebe zu, dass ich Erfahrungen in einer anderen Datenbank (Pervasive) gesammelt habe, aber das Gleiche gilt möglicherweise für alle Engines. Meine Anzahl von Werten pro Satz war 500-1000. Mehr oder weniger war deutlich langsamer.
quelle