3 Stimmen

Optimiere SELECT ... WHERE IN (...)

Ich erhalte eine Sequenz von Produkt-IDs aus einem externen System. Ich muss die Produktinformationen unter Beibehaltung der Reihenfolge anzeigen.

Ich verwende die folgende Abfrage, um dies zu tun:

SELECT * FROM  products
WHERE  prodid in (10331,11639,12127..) ORDER BY Field(prodid, 10331,11639,12127...);

Die Sequenz kann aus 20 IDs bestehen. Prodid hat einen b-tree Index.

Es handelt sich um eine sehr häufige Abfrage, und ich versuche, Möglichkeiten zu finden, um die Leistung dieses Teils des Systems zu verbessern. Derzeit beträgt die durchschnittliche Zeit für diese Abfrage 0,14-0,2 Sekunden. Ich würde gerne die Zeit auf 0,01-0,05 Sekunden verkürzen.

Wie kann ich das am besten erreichen? MySQL HASH-Index, Speichern der Produkt-ID in Memcached oder etwas anderes?

0 Stimmen

Was ist der Datentyp der prodid Spalte? Wie viele Produkt-IDs sind normalerweise im IN-Ausdruck?

0 Stimmen

Prodid ist INT (prodid < 100 000), IN besteht normalerweise aus 20 IDs.

0 Stimmen

Gibt es eine zusätzliche Beziehung zwischen den Daten, die durch direkte IDs ausgewählt wurden? Der Engpass könnte darin liegen, dass bei der Auswahl kleiner Datenmengen 20 Mal pro Abfrage über eine (vermutlich große) Datenbank gesprungen wird. Ein Clustering nach einem anderen Parameter könnte eine Option sein.

2voto

Johan Punkte 72893
SELECT * FROM  Produkte                         <<-- select * ist nicht optimal
WHERE  prodid in (10331,11639,12127..) 
ORDER BY Field(prodid, 10331,11639,12127...);   <<-- dein Problem ist hier

Zuerst setzen Sie einen Index auf prodid siehe Antwort von @Anthony.

Dann ändern Sie die Abfrage wie folgt:

SELECT only,the,fields,you,need FROM  Produkte
WHERE  prodid in (10331,11639,12127..) 
ORDER BY prodid

Wenn Sie sicherstellen, dass Ihre IN-Liste vor dem Angebot an die IN-Klausel aufsteigend sortiert ist, wird das order by prodid das gleiche Ergebnis liefern wie order by field(...

  • Die Verwendung einer Funktion anstelle eines Feldes beseitigt die Möglichkeit der Verwendung eines Index und verursacht Langsamkeit.
  • select * holt Daten, die Sie möglicherweise nicht benötigen, verursacht zusätzlichen Zugriff auf die Festplatte und zusätzlichen Speicherbedarf sowie zusätzlichen Netzwerkverkehr.
  • Bei InnoDB, wenn Sie nur indexierte Felder selecten, liest MySQL niemals die Tabelle, sondern nur den Index und spart Zeit (in Ihrem Fall ist dies wahrscheinlich jedoch kein Problem)

Was ist der beste Weg, dies zu tun? MySQL HASH-Index, Speichern von Produkt IDs in Memcached oder etwas anderes?

Es gibt ein paar Tricks, die Sie verwenden können.

  • Wenn die Produkte-Tabelle nicht zu groß ist, können Sie sie zu einer memory-Tabelle machen, die im RAM gespeichert ist. Machen Sie dies nicht für große Tabellen, es wird andere Dinge verlangsamen.
    Sie können nur hash-Indizes auf Memory-Tabellen verwenden.
  • Wenn die prodid's kontinuierlich sind, können Sie statt IN (1000, 1001 ..., 1019) BETWEEN 1000 AND 1019 verwenden.

0 Stimmen

Eigentlich ist ORDER BY Field - keine Funktion, sondern eine interne Konstruktion von MySQL zur Festlegung der Ausgabereihenfolge. Es handelt sich lediglich um eine Methode zur Beibehaltung der Ausgabereihenfolge. Wenn ich auf diese Konstruktion verzichte, werden die Produktinformationen in zufälliger Reihenfolge angezeigt.

1 Stimmen

@Andre, du liegst falsch, sieh dir die letzte Bearbeitung in meinem Beitrag an. Verwende immer einen Spaltennamen in einer order by-Klausel und nie eine Funktion. Field() ist eine Funktion, siehe hier: dev.mysql.com/doc/refman/5.0/de/… (beachte das Wort Funktion in der URL)

0 Stimmen

Ich kann IDs nicht aufsteigend oder auf irgendeine Weise sortieren - ich muss die Reihenfolge der Produkte in der Liste beibehalten. Um ehrlich zu sein, wähle ich nicht alle Felder mit *. Also, als Schlussfolgerung - muss ich "order by field" entfernen und die Sortierung in meiner Software durchführen?

1voto

Karolis Punkte 9247

Sie können versuchen, eine Vereinigung von Ergebnissen zu erstellen:

SELECT * FROM  products WHERE prodid = 10331
UNION ALL
SELECT * FROM  products WHERE prodid = 11639
UNION ALL
.
.
UNION ALL
SELECT * FROM  products WHERE prodid = 12127

0voto

Anthony Claeys Punkte 231

Sie könnten versuchen, einen Index auf der prodid Spalte mit der folgenden Abfrage zu setzen:

CREATE INDEX index_name
ON products (prodid); 

Weitere Informationen finden Sie unter diesem Beitrag.

1 Stimmen

Prodid hat bereits einen B-Tree-Index, ich habe das gerade erwähnt

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X