IN WHERE-Bedingung der Unterabfrage beeinflusst Hauptabfrage - Ist das eine Funktion oder ein Fehler?

8

Nehmen Sie die zwei Tabellen an:

%Vor%

In den folgenden Beispielen ist is something eine Bedingung, die mit einem festen Wert verglichen wird, z. B. = 'ABC' oder < 45 .

Ich habe eine Abfrage wie die folgende erstellt (1) :

%Vor%

Was ich wirklich schreiben wollte, war (2) :

%Vor%

Seltsamerweise haben beide Abfragen dasselbe Ergebnis zurückgegeben. Wenn Sie sich den explain-Plan der Abfrage 1 anschauten, sah es so aus, als wäre die Unterabfrage ausgeführt worden, weil die Bedingung A2 is something nicht auf die Unterabfrage anwendbar war > zurückgestellt zur Verwendung als Filter für die Hauptabfrageergebnisse.

Normalerweise würde die Abfrage 1 fehlschlagen, weil die Unterabfrage für sich selbst fehlschlagen würde:

%Vor%

Aber ich finde, dass dies nicht der Fall ist, und Postgres schreibt nicht zutreffende Unterabfragebedingungen auf die Hauptabfrage zurück.

Ist das Standardverhalten oder eine Postgres-Anomalie? Wo ist das dokumentiert und wie heißt dieses Feature?

Ich finde auch, dass, wenn ich eine Spalte A2 in der Tabelle B hinzufüge, nur die Abfrage 2 wie ursprünglich geplant funktioniert. In diesem Fall verweist der Verweis A2 in der Abfrage 2 immer noch auf A.A2 , aber die Referenz in der Abfrage 1 würde auf die neue Spalte B.A2 verweisen, weil dies der Fall ist ist jetzt direkt in der Unterabfrage anwendbar.

    
ADTC 16.12.2013, 04:17
quelle

4 Antworten

5

Ausgezeichnete Frage hier, etwas, dass viele Leute rüberkommen, aber nicht die Mühe machen, aufzuhören und zu schauen.

Sie schreiben eine Unterabfrage in der WHERE -Klausel; keine Inline-Ansicht in der FROM -Klausel. Da ist der Unterschied.

Wenn Sie eine Unterabfrage in SELECT oder WHERE -Klauseln schreiben, können Sie auf die Tabellen zugreifen, die sich in der FROM -Klausel der Hauptabfrage befinden. Dies geschieht nicht nur in Postgres, sondern ist ein Standardverhalten und kann in allen führenden RDBMS, einschließlich Oracle, SQL Server und MySQL beobachtet werden.

Wenn Sie die erste Abfrage ausführen, überprüft das Optimierungsprogramm Ihre gesamte Abfrage und bestimmt, wann nach welchen Bedingungen gesucht werden soll. Dieses Verhalten des Optimierungsprogramms zeigt, dass die Bedingung zurückgestellt für die Hauptabfrage ist, da das Optimierungsprogramm feststellt, dass es schneller ist, diese Bedingung in der Hauptabfrage selbst zu bewerten, ohne das Endergebnis zu beeinflussen.

Wenn Sie nur die Unterabfrage ausführen, indem Sie die Hauptabfrage auskommentieren, wird zwangsläufig ein Fehler an der Position zurückgegeben, die Sie erwähnt haben, da die Spalte, auf die verwiesen wird, nicht gefunden wird.

In Ihrem letzten Absatz haben Sie erwähnt, dass Sie der Tabelle A2 eine Spalte tableB hinzugefügt haben. Was du beobachtet hast, ist richtig. Dies geschieht aufgrund des impliziten Referenzphänomens. Wenn Sie den Tabellenalias für eine Spalte nicht angeben, sucht das Datenbankmodul in der Tabelle in der FROM -Klausel der Unterabfrage zuerst nach der Spalte. Nur wenn die Spalte dort nicht gefunden wird, wird auf die Tabellen in der Hauptabfrage verwiesen. Wenn Sie die folgende Abfrage verwenden, würde es immer noch das gleiche Ergebnis zurückgeben:

%Vor%

Vielleicht finden Sie weitere Informationen in Korths Buch über die relationale Datenbank, aber ich bin mir nicht sicher. Ich habe Ihre Frage soeben basierend auf meinen Beobachtungen beantwortet. Ich weiß, dass das passiert und warum. Ich weiß nur nicht, wie ich Ihnen weitere Referenzen geben kann.

    
Rachcha 16.12.2013, 05:21
quelle
2

Korrelierte Unterabfrage: - Wenn das Ergebnis einer Unterabfrage vom Wert einer Spalte der übergeordneten Abfragetabelle abhängt, wird die Unterabfrage als Korrelierte Unterabfrage bezeichnet. Es ist Standardverhalten, kein Fehler.

Es ist nicht erforderlich, dass die Spalte, auf die die korrelierte Abfrage angewiesen ist, in der ausgewählten Spaltenliste der übergeordneten Abfrage enthalten ist.

%Vor%

A2 ist eine Spalte der Tabelle A und die übergeordnete Abfrage befindet sich in Tabelle A. Das bedeutet, dass A2 in der Unterabfrage referenziert werden kann. Die obige Abfrage funktioniert möglicherweise langsamer als die folgende Abfrage.

%Vor%

Dies liegt daran, dass A2 von der übergeordneten Abfrage in der Schleife referenziert wird. Es hängt von der Bedingung ab, dass die Daten abgerufen werden. Wenn Unterabfrage etwas wie

ist %Vor%

Wir müssen auf die übergeordnete Abfrage-Spalte verweisen. Alternativ können wir Joins verwenden.

    
Airan 16.12.2013 06:23
quelle
2

Sie haben bereits eine Erklärung, warum korrelierte Unterabfragen in der WHERE -Klausel auf alle Spalten aus Tabellen in der FROM -Liste verweisen können.

Abgesehen davon, verwenden Sie eine JOIN oder ein EXISTS Semi-Join ist oft wesentlich schneller als korrelierte Unterabfragen. Ich würde diese 100% äquivalente Abfrage umschreiben:

%Vor%

Oder besser noch:

%Vor%     
Erwin Brandstetter 16.12.2013 08:19
quelle
0

Die Ergebnisse sind nicht seltsam, die Unterabfrage kann auf die PARENT-Abfrage verweisen. Dies wird als korrelierte Unterabfrage bezeichnet und ist sehr häufig. In Ihrem Beispiel verwendeten Sie den IN-Operator, aber normalerweise, um eine Abfrage mit der IN-Operation zu OPTIMIEREN, ersetzen Sie IN mit dem EXISTS-Operator, der eine korrelierte Unterabfrage verwendet.

Um Erwins Kommentar zu EXISTS, der schneller ist, zu erklären, liegt das daran, dass wenn Sie IN verwenden, "manchmal" die Abfrage benötigt, um alle Werte des Satzes zu finden. Für die Verwendung von EXISTS muss lediglich das erste Vorkommen gefunden werden, um die Bedingung zu erfüllen. Es ist jedoch möglich, dass der Abfrageplan optimiert, dass beide identisch sind. Die Verwendung von EXISTS unterstützt den Optimizer jedoch ausdrücklich dabei, den beabsichtigten Abfrageplan schneller zu erstellen.

    
CodeCowboyOrg 20.12.2013 16:17
quelle