Wenn ich einen Cte wie den folgenden Code habe. Wie oft wird der Tisch abgefragt? Ich hatte den Eindruck, dass es nur einmal aufgerufen und im Speicher gespeichert wurde, aber einige meiner Abfragen, die ich ausgeführt habe, scheinen viel länger zu laufen, als sie sein sollten. Was mich glauben lässt, dass es 3 Mal auf den People Table trifft.
with ctegeneric as (select person from people where person = 'dumb')
Select * from ctegeneric
UNION ALL
Select * from ctegeneric
UNION ALL
Select * from ctegeneric
sql-server
sql-server-2008-r2
cte
scripter78
quelle
quelle
In SQL kann ein CTE nur in der (one) -Anweisung verwendet / referenziert werden, in der er definiert ist. Und wir wissen, wo Anweisungen enden, indem wir Anweisungsterminatoren (
;
) verwenden.SQL Server verzeiht und erlaubt Entwicklern, diese Terminatoren nicht zu setzen (außer in besonderen Fällen, in denen es sich beschwert), aber es ist wirklich eine gute Praxis (und Microsoft empfiehlt es), sie nach jeder Anweisung zu verwenden. Wenn Sie sie platziert hätten, wäre es offensichtlich, dass Ihr Code als 3 Anweisungen analysiert wird:
Ihre zweite und dritte Anweisung sollten also überhaupt nicht funktionieren und geben den Fehler zurück:
INVALID OBJECT NAME: ctegeneric
Sobald die Aussage, wo der CTE gemacht wird, endet, verlieren Sie die Fähigkeit, ihn erneut zu referenzieren.
Es ist so ähnlich (dies ist auch keine gültige Syntax, nur eine andere Art, über CTEs nachzudenken):
Sie können die drei Auswahlen jedoch mit einem
UNION/UNION ALL
:quelle
Der Optimierer nimmt das übermittelte SQL und übersetzt es in eine Reihe von Aktionen, die als Abfrageplan bezeichnet werden. Dabei ist es frei, diese Aktionen in einer beliebigen Reihenfolge anzuordnen, die logisch der SQL entspricht. Dies kann dazu führen, dass auf ein in der SQL erwähntes Objekt einmal, mehrmals oder gar nicht zugegriffen wird. Dies gilt für Objekte im CTE.
Obwohl allgemein beobachtet wird, dass auf Objekte, die im CTE erwähnt werden, nur dann zugegriffen wird, gibt es keine Garantie dafür, dass dies geschieht.
Wie bei jeder anderen SQL-Anweisung gelten die über den CTE-Teil verarbeiteten Daten nur für die Dauer dieser Anweisung. Wenn in einer nachfolgenden Anweisung auf dieselben Daten verwiesen wird, wird erneut darauf zugegriffen.
quelle
Dieser Code funktioniert nicht wirklich.(op aktualisiertes Skript, nachdem diese Antwort veröffentlicht wurde)CTEs sind effektiv Unterabfragen (die die Rekursion unterstützen). Sie können nur im Rahmen dieses bestimmten Befehls referenziert werden. Als solches würde Ihre erste select * -Anweisung funktionieren, die nächsten beiden würden den Fehler machen, den CTE nicht finden zu können. Damit diese funktionieren, müssen Sie für jede Referenz einen anderen CTE erstellen. Und in dieser Situation würden Sie die Personentabelle dreimal treffen, einmal für jede Abfrage.
Um dies zu verbessern, können Sie Ihre Ergebnisse entweder in eine temporäre Tabelle oder in eine Tabellenvariable einfügen und diese dann einfach abfragen.
quelle