Geschwindigkeit des IN-Schlüsselwortes in MySQL / PostgreSQL

8

Ich habe viele Leute gehört, die sagen, dass das Schlüsselwort IN in den meisten relationalen Datenbanken langsam ist. Wie wahr ist das? Eine Beispielabfrage wäre das, ganz oben auf meinem Kopf:

%Vor%

Ich habe gehört, dass das viel langsamer ist als das:

%Vor%

Stimmt das? Oder ist die Geschwindigkeitsdifferenz vernachlässigbar? Wenn es darauf ankommt, verwende ich PostgreSQL, aber ich würde auch gerne wissen, wie MySQL läuft (und wenn es anders ist). Vielen Dank im Voraus.

    
Sasha Chedygov 05.06.2009, 18:36
quelle

7 Antworten

13

In PostgreSQL hängt das, was Sie hier bekommen, genau von der zugrundeliegenden Tabelle ab. Daher sollten Sie EXPLAIN ANALYZE bei einigen Beispielabfragen gegen eine nützliche Teilmenge Ihrer Daten verwenden, um genau herauszufinden, was der Optimierer tun wird (stellen Sie sicher die Tische, gegen die du spielst, wurden ebenfalls analysiert). IN kann auf verschiedene Arten verarbeitet werden. Deshalb müssen Sie sich einige Beispiele ansehen, um herauszufinden, welche Alternative für Ihre Daten verwendet wird. Es gibt keine einfache generische Antwort auf Ihre Frage.

Was die spezifische Frage betrifft, die Sie in Ihrer Revision hinzugefügt haben, ist hier ein Beispiel für die zwei Abfragepläne, die Sie erhalten, gegen einen trivialen Datensatz ohne Indizes:

%Vor%

Diese beiden Laufzeiten sind im Wesentlichen identisch, da die tatsächliche Verarbeitungszeit vom sequentiellen Scan über die Tabelle dominiert wird; mehrmals laufen zeigt den Unterschied zwischen den beiden ist unterhalb der Run to Run Fehlerspanne. Wie Sie sehen können, transformiert PostgreSQL den Fall IN so, dass er seinen ANY-Filter verwendet, der immer schneller als eine Reihe von ORs ausgeführt werden sollte. Auch hier ist dieser triviale Fall nicht unbedingt repräsentativ für das, was Sie bei einer ernsthaften Abfrage sehen werden, bei der es um Indizes und dergleichen geht. Unabhängig davon sollte das manuelle Ersetzen von INs durch eine Reihe von OR-Anweisungen niemals schneller sein, da der Optimierer hier die beste Vorgehensweise kennt, wenn er über gute Daten verfügt.

Im Allgemeinen kennt PostgreSQL mehr Tricks, um komplizierte Abfragen zu optimieren als der MySQL-Optimierer, aber es hängt auch stark davon ab, dass Sie dem Optimierer genügend Daten zur Verfügung gestellt haben. Die ersten Links im Abschnitt "Leistungsoptimierung" des PostgreSQL-Wiki decken die wichtigsten Dinge ab, die benötigt werden, um gute Ergebnisse vom Optimierer zu erhalten.

    
Greg Smith 05.06.2009, 19:19
quelle
8

In MySQL sind dies vollständige Synonyme für den Optimierer:

%Vor%

und

%Vor%

, vorausgesetzt, dass value Literale contants oder voreingestellte Variablen sind.

Laut Dokumentation :

  

Die Definition einer Bereichsbedingung für einen einteiligen Index lautet wie folgt:

     
  • Für die beiden Indizes BTREE und HASH ist der Vergleich eines Schlüsselteils mit einem konstanten Wert eine Bereichsbedingung bei Verwendung von = , <=> , IN() , IS NULL oder IS NOT NULL . Betreiber.
  •   
  • ...
  •   
  • Für alle Arten von Indizes bilden mehrere Bereichsbedingungen in Kombination mit OR oder AND eine Bereichsbedingung.
  •   

"Konstanter Wert" in den vorhergehenden Beschreibungen bedeutet eine der folgenden:

     
  • Eine Konstante aus der Abfragezeichenfolge
  •   
  • Eine Spalte einer Konst- oder Systemtabelle aus demselben Join
  •   
  • Das Ergebnis einer unkorrelierten Unterabfrage
  •   
  • Jeder Ausdruck, der vollständig aus Unterausdrücken der vorhergehenden Typen besteht
  •   

Diese Abfrage jedoch:

%Vor%

verwendet den Index für id , während dieser:

%Vor%

verwendet fullscan.

Ich. e. Es gibt Unterschiede, wenn eine der value eine einreihige Unterabfrage ist.

Ich habe es kürzlich als Fehler 45145 in% co_de eingereicht % (es stellte sich heraus, dass MySQL spezifisch ist, nicht in 5.2 und korrigiert in 5.1 )

    
Quassnoi 05.06.2009 19:33
quelle
5

Die Verwendung von IN ist nicht unbedingt langsam, es ist die Art, wie Sie die IN-Parameter erstellen, die die Dinge erheblich verlangsamen. Zu oft verwenden die Benutzer SELECT ... WHERE x IN (SELECT ...), was sehr schlecht optimiert werden kann (d. H. Überhaupt nicht.) Suchen Sie nach "correlated subquery", um zu sehen, wie schlecht es sein kann.

Oft müssen Sie IN überhaupt nicht verwenden und stattdessen einen JOIN verwenden und die abgeleiteten Tabellen nutzen.

%Vor%

Kann so umformuliert werden

%Vor%

Wenn die IN-Syntax langsam ist, ist die JOIN-Syntax oft viel schneller. Sie können EXPLAIN verwenden, um zu sehen, wie jede Abfrage anders optimiert wird. Dies ist ein einfaches Beispiel und Ihre Datenbank zeigt möglicherweise den gleichen Abfragepfad, aber kompliziertere Abfragen zeigen normalerweise etwas anderes.

    
Brent Baisley 05.06.2009 19:48
quelle
1

IN mit einem Subselect ist oft langsam. IN mit einer Werteliste sollte nicht langsamer sein als someColumn = value1 ODER someColumn = value2 OR someColumn = value3 usw. Das ist viel schneller, solange die Anzahl der Werte vernünftig ist.

IN mit einer Unterabfrage ist langsam, wenn der Optimierer keinen guten Weg findet, die Abfrage auszuführen, und er muss die offensichtliche Methode verwenden, um das vollständige Ergebnis der Unterabfrage aufzubauen. Zum Beispiel:

%Vor%

wird viel langsamer sein als

%Vor%

es sei denn, der Optimierer kann herausfinden, was Sie gemeint haben.

    
derobert 05.06.2009 18:47
quelle
1

Ich denke, du hast die Antwort (en) bekommen, die du oben haben wolltest. Ich wollte nur eine Sache hinzufügen.

Sie müssen IN optimieren und es richtig verwenden. In der Entwicklung richte ich immer einen Debug-Bereich am unteren Ende der Seite ein, wenn eine Anfrage erscheint und führt automatisch EXPLAIN EXTENDED bei jedem SELECT und dann SHOW WARNINGS aus, um zu sehen, wie (wahrscheinlich) MySQL Query Optimizer umschreibt die Abfrage intern. Es gibt viel zu lernen, wie Sie sicherstellen können, dass IN für Sie arbeitet.

    
joedevon 06.06.2009 02:07
quelle
0

Die Geschwindigkeit des IN-Schlüsselworts hängt wirklich von der Komplexität Ihrer Unterabfrage ab. In dem von Ihnen bereitgestellten Beispiel möchten Sie nur sehen, ob sich der Wert für einige Spalten in einer festgelegten Liste von Werten befindet, und zwar ziemlich kurz. Also würde ich mir vorstellen, dass die Performance-Kosten in diesem Fall sehr gering wären.

    
Matthew Vines 05.06.2009 18:45
quelle
0

In den Dokumenten steht, dass IN in MySQL sehr schnell ist, aber ich kann die Quelle im Moment nicht finden.

    
Greg 05.06.2009 18:39
quelle

Tags und Links