2012-08-25 9 views
10

Die folgenden beiden Abfragen liefern genau das gleiche Ergebnis:Ist die HAVING-Klausel redundant?

select country, count(organization) as N 
from ismember 
group by country 
having N > 50; 

select * from (
    select country, count(organization) as N 
    from ismember 
    group by country) x 
where N > 50; 

Kann jeder HAVING Klausel durch eine Unterabfrage und einer WHERE Klausel wie folgt ersetzt werden? Oder gibt es Situationen, in denen eine HAVING Klausel absolut notwendig/leistungsfähiger/effizienter/was auch immer ist?

+3

Sie sollten RDBMS auf die Frage, die ich denke, definieren. Ihre erste Abfrage ist in SQL Server 2008 nicht gültig, da Sie in der Auswahl auf einen Alias ​​nicht verweisen können. Nur im OrderBy-Teil, wegen der logischen Abfrageverarbeitung. –

+0

Ich vermute MySQL? Die erste Abfrage ist in Oracle aus dem gleichen Grund nicht gültig. – Ben

+0

@Ben Ja, ich habe gerade den MySQL-Tag zur Klärung hinzugefügt. Vielen Dank. – fredoverflow

Antwort

9

Es gibt zwei Fragen hier: Die Antwort auf die erste davon ist ja: Die resultset einer HAVING beladene Abfrage ist identisch mit der des Suchresultates der gleichen Abfrage als Unterabfrage ausgeführt, mit einer WHERE Klausel dekoriert .

Die zweite Frage bezieht sich auf Leistung und Expressivität - hier gehen wir stark in die Umsetzung. Auf MySQL gibt es eine dünne rote Linie, wo die Performance auseinander zu driften beginnt: In dem Moment, in dem das Resultset der inneren Abfrage nicht mehr im Speicher gehalten werden kann. In diesem Fall erstellt MySQL eine Darstellung der inneren Abfrage auf der Festplatte und verwendet dann den Selektor WHERE. Dies wird nicht passieren, wenn die Klausel HAVING verwendet wird, wird die disqualifizierte Gruppe aus der Ergebnismenge entfernt.

Dies impliziert, dass je höher die Selektivität der Klausel ist, desto mehr Leistungsrelevanz hat es: Betrachten Sie Ergebnismenge von einer Million Zeilen der inneren Abfrage, die durch die HAVING Klausel auf 5 Zeilen reduziert wird - es ist sehr wahrscheinlich, dass die Ergebnismenge der inneren Abfrage nicht im Speicher gehalten wird, aber es ist sehr wahrscheinlich, dass das endgültige Ergebnis gesetzt würde.

bearbeiten

hatte ich dieses ein Mal: ​​Die Abfrage, die wenige Ausreißer von einer sehr gleichmäßig verteilt Tabelle (Anzahl der Stücke auf einer physische Maschine pro Tag in einer Werkstatt hergestellt) ausgewählt. Ich habe wegen der hohen IO-Last untersucht.

Edit 2

Bitte beachten Sie, dass die Abfrage-Cache ist für Subqueries nicht benutzt - IMHO ein Ort Entwicklung sollte mehr auf das Wesentliche konzentrieren - so die Unterabfrage Muster wird nicht von der inneren Abfrage Wesen profitieren eine zwischengespeicherte Ergebnismenge.

+0

+1 Gut, um die Datenmenge zu berücksichtigen. –

0

IMHO sollte die Verwendung der -Klausel effizient sein, da es einen zusätzlichen Durchlauf auf der Arbeitstabelle geben würde, die die gruppierten Ergebnisse enthält, auf denen die Filterkriterien ausgeführt werden, im zweiten Fall.

+0

Sub-Abfragen nicht in Arbeitstische erweitert werden. Die beiden Abfragen (obwohl das Alias-Problem für andere Plattformen entfernt wurde) sollten identisch behandelt werden. –

+0

@RobFarley Das ist nicht ganz richtig: Wenn das Resultset eine bestimmte Größe überschreitet, wird es materialisiert. –

+1

Ok. Nicht in SQL Server oder Oracle. Diese Systeme vereinfachen die Abfrage. –

4

Die HAVING-Klausel ist sehr nützlich, um die zusätzliche Komplexität von Unterabfragen zu vermeiden. Die beiden sind jedoch logisch äquivalent und jede HAVING-Klausel kann wie eine Unterabfrage mit einer Unterabfrage neu geschrieben werden.

Falls Sie neugierig sind, könnten Sie auch jede WHERE-Klausel als HAVING-Klausel schreiben, wenn Sie bereit sind, GROUP BY auf die Spitze zu treiben.

+0

Nicht sicher, ob deine letzte Zeile wahr ist, oder? Angenommen, eine Tabelle mit einer Spalte namens "number" und drei Zeilen "VALUES (1), (1), (2)" Wie kann man "SELECT Nummer VON T WHERE Nummer = 1" mit "HAVING" simulieren? –

+0

Sie würden GROUP BY Nummer. –

+0

Das würde nur eine Zeile zurückgeben. –

8

in SQL Server 2008 zwei ähnliche Fragen haben genau den gleichen Ausführungsplan:

enter image description here

Ich habe auch viele Anfragen, die von Entity Framework (SS 2008) und bisher untersuche ich nie sah eine Abfrage mit einer HAVING Klausel. Gruppierungsabfragen mit einer Bedingung für ein aggregiertes Ergebnis werden immer in eine Abfrage mit einer Unterabfrage übersetzt. Ich vertraue der ADO.Net-Team weiß, dass sie es tun ...

+0

Ich würde das überhaupt nicht vertrauen. EF (und Linq-to-SQL) produzieren notorisch schlechte Abfragen. –

+0

Ich habe gerade das gleiche versucht :) + 1 Sie waren der schnellere :) –

+1

@RobFarley Ich weiß, dass sie nicht mit manuell gestalteten und optimierten Abfragen konkurrieren können, aber für automatisierte Abfragen sind sie nicht so schlecht. Sie sollten aber einige Dinge wissen, wenn Sie linq schreiben. –

0

Ich weiß, dass Sie es von allgemein zu MySQL geändert haben, aber ich möchte hier eine (möglicherweise nützliche) Notiz hinzufügen. Mit etwas Modifikation I Ihre Abfrage in SQL Server versucht, 2008

Nur für alle, die ausführlicher in es will, ist die executionplan der beide Abfrage sogar genau die gleichen in SQL Server 2008. So ist die Optimizer verarbeitet die beiden Befehle auf die gleiche Weise mit der gleichen Leistung und Schätzungen.

0

Logisch ja das Ergebnis wird am Ende gleich sein. Aber die Leistung kann abweichen. Die HAVING-Klausel kann dazu führen, dass die DB einen anderen Ausführungsplan ändert.

Ein Hinweis an die Jungs oben (kann nicht direkt irgendwie kommentieren) - der Ausführungsplan hängt nicht nur von Ihrer Anfrage ab. Es kann auch von der Datenbank abhängig von Statistiken wie Tabellengröße usw. zur Laufzeit angepasst werden. Das heißt für DB2 mindestens ...

Verwandte Themen