Wenn ich in einer Tabelle nach einer Zeile suchen muss, schreibe ich in der Regel immer eine Bedingung wie:
SELECT a, b, c
FROM a_table
WHERE EXISTS
(SELECT * -- This is what I normally write
FROM another_table
WHERE another_table.b = a_table.b
)
Einige andere Leute schreiben es so:
SELECT a, b, c
FROM a_table
WHERE EXISTS
(SELECT 1 --- This nice '1' is what I have seen other people use
FROM another_table
WHERE another_table.b = a_table.b
)
Wenn die Bedingung ist NOT EXISTS
statt EXISTS
: In einigen Fällen könnte ich es schreibe mit ein LEFT JOIN
und einer zusätzlichen Bedingung (manchmal ein genannt antijoin ):
SELECT a, b, c
FROM a_table
LEFT JOIN another_table ON another_table.b = a_table.b
WHERE another_table.primary_key IS NULL
Ich versuche es zu vermeiden, weil ich denke, dass die Bedeutung weniger klar ist, besonders wenn das, was Ihr primary_key
ist, nicht so offensichtlich ist, oder wenn Ihr Primärschlüssel oder Ihre Join-Bedingung mehrspaltig ist (und Sie leicht eine der Spalten vergessen können). Manchmal behält man jedoch Code bei, der von jemand anderem geschrieben wurde ... und der ist einfach da.
Gibt es einen Unterschied (außer Stil) zu verwenden,
SELECT 1
anstattSELECT *
?
Gibt es einen Eckfall, in dem es sich nicht gleich verhält?Obwohl das, was ich geschrieben habe, (AFAIK) Standard-SQL ist: Gibt es einen solchen Unterschied für verschiedene Datenbanken / ältere Versionen?
Gibt es einen Vorteil, wenn explizit ein Antijoin geschrieben wird?
Behandeln zeitgenössische Planer / Optimierer dies anders als in derNOT EXISTS
Klausel?
quelle
EXISTS (SELECT FROM ...)
.Antworten:
Nein, es gibt keinen Unterschied in der Effizienz zwischen
(NOT) EXISTS (SELECT 1 ...)
und(NOT) EXISTS (SELECT * ...)
in allen wichtigen DBMS. Ich habe oft gesehen(NOT) EXISTS (SELECT NULL ...)
, wie man es benutzt.In manchen kann man sogar schreiben
(NOT) EXISTS (SELECT 1/0 ...)
und das Ergebnis ist das gleiche - ohne irgendeinen (Division durch Null) Fehler, was beweist, dass der Ausdruck dort nicht einmal ausgewertet wird.Über die
LEFT JOIN / IS NULL
Antijoin-Methode erfolgt eine Korrektur: Dies entsprichtNOT EXISTS (SELECT ...)
.In diesem Fall
NOT EXISTS
vsLEFT JOIN / IS NULL
Es kann sein, dass Sie unterschiedliche Ausführungspläne erhalten. In MySQL zum Beispiel und meist in älteren Versionen (vor 5.7) wären die Pläne ziemlich ähnlich, aber nicht identisch. Die Optimierer anderer DBMS (SQL Server, Oracle, Postgres, DB2) sind meines Wissens mehr oder weniger in der Lage, diese beiden Methoden umzuschreiben und die gleichen Pläne für beide zu berücksichtigen. Es gibt jedoch keine solche Garantie und wenn Sie eine Optimierung durchführen, ist es gut, die Pläne von verschiedenen äquivalenten Umschreibungen zu überprüfen, da es Fälle geben kann, in denen die einzelnen Optimierer nicht umschreiben (z. B. komplexe Abfragen mit vielen Verknüpfungen und / oder abgeleiteten Tabellen). Unterabfragen innerhalb der Unterabfrage (Bedingungen aus mehreren Tabellen, zusammengesetzte Spalten, die in den Verbindungsbedingungen verwendet werden) oder die Optimierungsoptionen und -pläne werden von den verfügbaren Indizes, Einstellungen usw. unterschiedlich beeinflusst.Beachten Sie auch, dass
USING
dies nicht in allen DBMS verwendet werden kann (z. B. SQL Server). Das allgemeinereJOIN ... ON
arbeitet überall.Und den Spalten muss der Tabellenname / Alias vorangestellt werden
SELECT
, um Fehler / Mehrdeutigkeiten bei Verknüpfungen zu vermeiden.Normalerweise ziehe ich es auch vor, die verknüpfte Spalte in die
IS NULL
Prüfung einzubeziehen (obwohl die PK oder jede nicht nullfähige Spalte in Ordnung wäre, könnte dies aus Gründen der Effizienz hilfreich sein, wenn der PlanLEFT JOIN
einen nicht gruppierten Index verwendet):Es gibt auch eine dritte Methode für Antijoins, die
NOT IN
jedoch eine andere Semantik (und andere Ergebnisse!) Verwendet, wenn die Spalte der inneren Tabelle nullwertfähig ist. Es kann jedoch durch Ausschließen der Zeilen mit verwendet werdenNULL
, wodurch die Abfrage den vorherigen 2 Versionen entspricht:Dies führt normalerweise auch zu ähnlichen Plänen in den meisten DBMS.
quelle
[NOT] IN (SELECT ...)
, obwohl gleichwertig, sehr schlecht. Vermeide es!SELECT *
macht sicherlich mehr Arbeit. Ich würde der Einfachheit halber ratenSELECT 1
Es gibt eine Kategorie von Fällen , in denen
SELECT 1
undSELECT *
nicht austauschbar sind - genauer gesagt, man wird immer vor allem in den Fällen , während der andere wird nicht akzeptiert.Ich spreche von Fällen, in denen Sie überprüfen müssen, ob Zeilen einer gruppierten Menge vorhanden sind. Wenn die Tabelle
T
Spalten enthältC1
undC2
Sie überprüfen, ob Zeilengruppen vorhanden sind, die einer bestimmten Bedingung entsprechen, können Sie Folgendes verwendenSELECT 1
:aber Sie können nicht
SELECT *
auf die gleiche Weise verwenden.Das ist nur ein syntaktischer Aspekt. Wenn beide Optionen syntaktisch akzeptiert werden, werden Sie höchstwahrscheinlich keinen Unterschied in Bezug auf die Leistung oder die zurückgegebenen Ergebnisse haben, wie in der anderen Antwort erläutert .
Zusätzliche Hinweise nach Kommentaren
Es scheint, dass nicht viele Datenbankprodukte diese Unterscheidung tatsächlich unterstützen. Produkte wie SQL Server, Oracle, MySQL und SQLite akzeptieren
SELECT *
die obige Abfrage gerne und fehlerfrei, was wahrscheinlich bedeutet, dass sie EXISTSSELECT
auf besondere Weise behandeln.PostgreSQL ist ein RDBMS, bei dem
SELECT *
möglicherweise ein Fehler auftritt, das jedoch in einigen Fällen noch funktioniert. Insbesondere, wenn Sie nach der PK gruppieren,SELECT *
funktioniert dies einwandfrei, andernfalls schlägt die Meldung fehl:quelle
GROUP BY
, das Konzept von*
ist bedeutungslos (oder zumindest nicht so klar).Eine wohl interessante Möglichkeit, die
EXISTS
Klausel neu zu schreiben, die zu einer saubereren und vielleicht weniger irreführenden Abfrage führt, wäre zumindest in SQL Server:Die Anti-Semi-Join-Version davon würde so aussehen:
Beide sind in der Regel auf den gleichen Plan wie
WHERE EXISTS
oder optimiertWHERE NOT EXISTS
, aber die Absicht ist unverkennbar, und Sie haben keine "seltsamen"1
oder*
.Interessanterweise sind die damit verbundenen Nullprüfungsprobleme
NOT IN (...)
problematisch<> ALL (...)
, wohingegen dieNOT EXISTS (...)
nicht unter diesem Problem leiden. Betrachten Sie die folgenden zwei Tabellen mit einer nullwertfähigen Spalte:Wir fügen beiden Daten hinzu, wobei einige Zeilen übereinstimmen und andere nicht:
Die
NOT IN (...)
Abfrage:Hat folgenden Plan:
Die Abfrage gibt keine Zeilen zurück, da die Gleichheit aufgrund der NULL-Werte nicht bestätigt werden kann.
Diese Abfrage
<> ALL (...)
zeigt denselben Plan und gibt keine Zeilen zurück:Die Variante using
NOT EXISTS (...)
, zeigt eine etwas andere Grundrissform und gibt Zeilen zurück:Der Plan:
Die Ergebnisse dieser Abfrage:
Dies macht die Verwendung
<> ALL (...)
genauso anfällig für problematische Ergebnisse wieNOT IN (...)
.quelle
*
es nicht seltsam: Ich leseEXISTS (SELECT * FROM t WHERE ...)
ASthere is a _row_ in table _t_ that...
. Wie dem auch sei, ich habe gerne Alternativen und deine ist klar lesbar. Ein Zweifel / Vorbehalt: Wie wird es sich verhalten, wennb
es nullbar ist? [Ich hatte schlechte Erfahrungen und einige kurze Nächte, als ich versuchte, einen Irrtum herauszufinden, der durch einen Fehler verursacht wurdex IN (SELECT something_nullable FROM a_table)
]Der "Beweis", dass sie identisch sind (in MySQL), ist zu tun
dann mit wiederholen
SELECT 1
. In beiden Fällen zeigt die "erweiterte" Ausgabe, dass sie in umgewandelt wurdeSELECT 1
.Ebenso
COUNT(*)
wird in verwandeltCOUNT(0)
.Noch etwas zu beachten: In den letzten Versionen wurden Optimierungsverbesserungen vorgenommen. Ein Vergleich mit
EXISTS
Anti-Joins kann sich lohnen . Ihre Version kann einen besseren Job mit einem gegen den anderen machen.quelle
In einigen Datenbanken funktioniert diese Optimierung noch nicht. Wie zum Beispiel in PostgreSQL Ab Version 9.6 schlägt dies fehl.
Und das wird gelingen.
Es schlägt fehl, weil das Folgende fehlschlägt, aber das bedeutet immer noch, dass es einen Unterschied gibt.
Weitere Informationen zu dieser besonderen Eigenart und zum Verstoß gegen die Spezifikation finden Sie in meiner Antwort auf die Frage: Benötigt die SQL-Spezifikation eine GROUP BY in EXISTS ()?
quelle
Ich habe immer verwendet
select top 1 'x'
(SQL Server)Theoretisch
select top 1 'x'
wäre dies effizienterselect *
, da erstere vollständig wären, nachdem eine Konstante für das Vorhandensein einer qualifizierenden Zeile ausgewählt worden wäre, während letztere alles auswählen würde.JEDOCH, obwohl es sehr früh relevant gewesen sein mag, hat die Optimierung den Unterschied in wahrscheinlich allen wichtigen RDBS irrelevant gemacht.
quelle
top n
ohneorder by
eine gute Idee sind.select top 1 'x'
sollte es nicht effizienter sein alsselect *
in einemExist
Ausdruck. In der Praxis ist es möglicherweise effizienter, wenn der Optimierer nicht optimal funktioniert, theoretisch sind jedoch beide Ausdrücke gleichwertig.IF EXISTS(SELECT TOP(1) 1 FROM
ist langfristig und plattformübergreifend eine bessere Angewohnheit, nur weil Sie sich nicht einmal Gedanken darüber machen müssen, wie gut oder schlecht Ihre aktuelle Plattform / Version ist. und SQL bewegt sich vonTOP n
zu parametrisierbarTOP(n)
. Dies sollte eine einmalige Lernfähigkeit sein.quelle
TOP
ist nicht einmal gültiges SQL.TOP (n)
in "SQL" - der Standard-Abfragesprache. Unter T-SQL gibt es einen Dialekt, den Microsoft SQL Server verwendet.