Welche Optimierungen und / oder Änderungen treten bei einer Abfrage auf, die für eine Ansicht ausgeführt wird? (Es wäre großartig zu wissen, ob alle wichtigen DBs - Oracle, SQL Server, Postgres, MySQL / MariaDB - dies anders handhaben.)
Nehmen wir zum Beispiel an, ich habe die folgende Ansicht:
CREATE VIEW my_view AS
SELECT
id,
val0,
val1,
val2
FROM my_table
WHERE val0 = 42;
... und ich möchte die folgende Abfrage für diese Ansicht ausführen:
SELECT
id,
val1
FROM my_view
WHERE val2 = 'Fish fingers and custard';
... optimiert die Datenbank die Abfrage oder werden im Wesentlichen zwei Auswahlen durchgeführt? IE ist es im Wesentlichen das gleiche wie die Durchführung der potenziellen Abfrage 1 oder 2 unten oder keine?
Mögliche Abfrage 1:
SELECT
id,
val1
FROM (
SELECT
id,
val0,
val1,
val2
FROM my_table
WHERE val0 = 42
)
WHERE val2 = 'Fish fingers and custard';
Mögliche Abfrage 2:
SELECT
id,
val1
FROM my_table
WHERE val0 = 42
AND val2 = 'Fish fingers and custard';
optimization
view
bsara
quelle
quelle
Antworten:
Meine Antwort konzentriert sich fast ausschließlich auf SQL Server, nur weil ich eine ziemlich detaillierte Antwort geben werde und nicht über das gleiche Fachwissen auf anderen Plattformen verfüge.
Zunächst ist es wichtig zu wissen, dass das Abfrageoptimierungsprogramm nicht direkt mit dem von Ihnen geschriebenen SQL funktioniert. Es wird vor der Optimierung in ein internes Format umgewandelt. Was Sie für potenzielle Abfrage 1 und Abfrage 2 aufgelistet haben, ist bis auf subtile Unterschiede in der Ansicht ziemlich dasselbe. Eine ähnliche Frage zum Unterschied zwischen Abfrage 1 und Abfrage 2 wurde hier gestellt und beantwortet . Wenn Sie mehr über das interne Format von SQL Server erfahren möchten, können Sie eine hervorragende Reihe von Blog-Posts von Paul White durchgehen . In den meisten Fällen reicht es jedoch aus, nur die Abfragepläne von zwei Abfragen zu vergleichen, von denen Sie vermuten, dass sie auf dieselbe Weise optimiert wurden.
Es gibt verschiedene Möglichkeiten, wie die Verwendung einer Ansicht die Leistung verbessern kann:
Es ist möglich, Ansichten zu definieren, die als physische Strukturen in der Datenbank implementiert sind. In SQL Server werden diese als indizierte Ansichten bezeichnet . In Oracle werden diese als materialisierte Ansichten bezeichnet. In Oracle kann eine Abfrage, die nicht für eine materialisierte Ansicht geschrieben wurde, weiterhin die materialisierte Ansicht verwenden. Weitere Diskussionen liegen außerhalb des Rahmens dieser Antwort.
Manchmal muss dieselbe SQL-Abfrage auf mehreren RDBMS-Plattformen ausgeführt werden. Mit einer Ansicht können wir eine Syntax verwenden, die für jede Plattform eindeutig ist, aber dieselbe Abfrage an die Datenbanken gesendet wird. Ohne eine Ansicht müssen wir möglicherweise benutzerdefinierte Funktionen verwenden, die die Leistung beeinträchtigen können.
Manchmal fügen Leute wirklich cleveren Code in Ansichten ein. Wenn es besser ist als das, was Sie geschrieben haben, können Sie die Leistung mithilfe der Ansicht verbessern.
Im Allgemeinen ist eine Abfrage, die für eine Ansicht geschrieben wurde, genauso effizient oder weniger effizient als eine Abfrage, die direkt für die Basistabellen geschrieben wurde. Dies liegt daran, dass eine Ansichtsdefinition häufig zusätzliche Spalten und Verknüpfungen enthält, die für die spezifische Frage, die eine Abfrage für die Ansicht stellt, möglicherweise nicht erforderlich sind. Um eine gute Leistung bei einer komplexen Sichtweise zu erzielen, hoffen wir, dass drei Dinge passieren:
Spalteneliminierung. Wenn eine Spalte in einer Ansicht dargestellt, aber in der Abfrage nicht für die Ansicht erwähnt wird, sollte der Wert nicht berechnet werden.
Eliminieren Sie die Eliminierung. Wenn eine Tabelle in einer Ansicht verwendet wird, die sicher entfernt werden kann, ohne die Ergebnisse zu ändern, sollte sie entfernt werden. Manchmal kann dies passieren, wenn der Optimierer mehr Informationen hat. Beispielsweise kann ein Fremdschlüssel nicht in der Datenbank deklariert werden. In anderen Fällen deckt die Regel zum Implementieren der Join-Eliminierung möglicherweise ein bestimmtes Szenario nicht ab. Beispielsweise kann in Oracle die Join-Eliminierung für einen mehrspaltigen Join nicht erfolgen, in SQL Server jedoch.
Prädikat Pushdown. Wenn ich der Ansicht einen Filter hinzufüge und die zugrunde liegende Spalte einen Index enthält, sollte ich diesen Index verwenden können. Ich glaube, das ist es, worauf Ihr Beispiel hinweist. Auch ohne Index möchte ich, dass die Filter so weit wie möglich in den Plan aufgenommen werden, um unnötige Arbeit zu vermeiden.
Nach meiner Erfahrung werden diese Regeln vom Abfrageoptimierer ziemlich gut implementiert, was natürlich eine gute Sache ist, aber für SE-Demos kann es schlecht sein. Wenn wir jedoch hinterhältigen Code schreiben, können wir Beispiele erhalten, die zeigen, dass alle oben genannten Optimierungen fehlschlagen. Dies liegt daran, dass die Regeln, die die Optimierungen implementieren, nicht für jedes mögliche Szenario ausgelegt sind.
Zuerst erstelle ich einige einfache Beispieldaten. Die Daten selbst sind nicht so wichtig, aber die Tabellendefinitionen.
Hier ist meine hinterhältige Ansichtsdefinition:
Die Aussicht ist leider ein Chaos. Als menschlicher Optimierer ist es möglich, diese Abfrage erheblich zu vereinfachen. Der Join gegen
EXTRA_TABLE
kann eliminiert werden, da wir gegen den vollständigen Primärschlüssel verbinden, sodass sich die Anzahl der Zeilen nicht ändert. Es ist auch nicht möglich, dass Zeilen übereinstimmen, aber es handelt sich um eine äußere Verknüpfung, sodass nichts beseitigt wird. Der Join gegenEMPTY_CCI
kann beseitigt werden, da die Join-Bedingung niemals übereinstimmt. Die Verknüpfung gegenEMPTY_TABLE
kann beseitigt werden, da wir gegen den vollständigen Primärschlüssel beitreten . Die Funktion kehrt auch immer zurück,NULL
sodass dies nicht berücksichtigt werden muss. Wir können dies also vereinfachen:Wir können es jedoch noch besser machen.
ID
ist aufgrund der Einschränkung immer positiv undID
immer eindeutig, da es sich um den Primärschlüssel handelt. DieCOUNT
Fensterfunktion ist also immer 1. Die Abfrage kann folgendermaßen umgeschrieben werden:Wird das Abfrageoptimierungsprogramm in der Lage sein, eine Abfrage gegenüber der Ansicht zu vereinfachen? Lassen Sie uns das herausfinden, indem wir die Pläne vergleichen. Hier ist der Plan für die einfache Abfrage:
Hier ist der Plan
SELECT *
gegen die Aussicht:Sie sind ziemlich unterschiedlich. Lassen Sie uns weitere Beispielabfragen durchgehen, um Beispiele für die obigen Optimierungen zu sehen, die möglicherweise nicht genau wie erwartet funktionieren.
Erstens sind skalare benutzerdefinierte Funktionen für die Leistung in SQL Server schlecht. Unter anderem zwingen sie die gesamte Abfrage zu einem seriellen Plan. Diese Abfrage ist für einen parallelen Plan berechtigt und ich erhalte einen auf meinem Computer:
Der Plan:
Selbst wenn ich die Spalte nicht basierend auf der benutzerdefinierten Funktion in der Ansicht auswähle, erhalte ich dennoch einen erzwungenen Serienplan:
Es gibt also einen Unterschied zwischen der Verwendung einer Ansicht und einer abgeleiteten Tabelle. Manchmal funktioniert die Spalteneliminierung nicht auf die gleiche Weise.
Im zweiten Beispiel wirkt sich die
EMPTY_CCI
Tabelle nicht auf die Ergebnisse der Abfrage aus. Entfernen Sie sie daher aus der abgeleiteten Tabelle:Hier ist der Abfrageplan:
Es gibt jedoch einen Unterschied im Abfrageplan gegenüber der Ansicht:
Der Blick ist in der Lage zu verwenden Batch - Modus , die eine besondere Art und Weise ist die Ausführung der Abfrage der Implementierung , wenn gruppiert columns Indizes in einer Abfrage beteiligt ist. Auch wenn die
EMPTY_CCI
Tabelle nicht im Plan angezeigt wird, kann die Abfrage weiterhin für den Stapelmodus verwendet werden. Beachten Sie, dass diesEXTRA_TABLE
in beiden Abfragen unnötig abgefragt wird. Dies liegt daran, dass die Join-Bedingung für SQL Server zu kompliziert war, um festzustellen, ob der Join sicher beseitigt werden konnte. Beachten Sie auch, dass dieEMPTY_TABLE
Tabelle in keinem der Abfragepläne angezeigt wird. Das Abfrageoptimierungsprogramm konnte es in beiden Abfragen entfernen.Schauen wir uns für das dritte Beispiel den Prädikat-Pushdown an. Nehmen wir an, ich möchte filtern, um nur Zeilen einzuschließen, in denen
ID = 500000
. Wenn ich das etwas direkt außerhalb der Ansicht mache:Ich kann den Index
BASE_TABLE.ID
aufgrund derABS()
Funktion nicht verwenden. Der Filter wird jedoch in den Scan gedrückt, und es wird erwartet, dass nur eine Zeile zurückgegeben wird. Das kann die Leistung verbessern:Mit dieser Abfrage:
Wir bekommen einen weniger effizienten Plan. Der Filter on
ID = 500000
wird ganz am Ende des Plans implementiert, sodass die Fensterfunktion anhand von fast einer Million unnötiger Zeilen bewertet wird:Das war vielleicht ein bisschen tiefer als das, wonach Sie gesucht haben. Wenn ich zu Ihrer ursprünglichen Frage zurückkehre, würde ich sagen, dass die Abfrage gegen die Ansicht der potenziellen Abfrage 1 am ähnlichsten ist. Ich habe Gerüchte über einige Fälle gehört, in denen dies nicht der Fall ist. Wenn Sie beispielsweise viele verschachtelte Ansichten haben, kann das Abfrageoptimierungsprogramm möglicherweise Schwierigkeiten haben, diese zu entpacken, und Sie können allein aus diesem Grund eine schlecht optimierte Abfrage erhalten. Ich weiß nicht, ob dies in einer aktuellen Version von SQL Server zutrifft, aber es lohnt sich, dies einfach zu vermeiden, damit andere Personen, die versuchen, Ihren Code zu verstehen, es leichter haben.
quelle
Für SQL Server (ich weiß nicht für andere Datenbanksysteme).
Wenn ich die select-Anweisung mit view und der zugrunde liegenden Tabelle ausführe, sehen Sie, dass Sie denselben Ausführungsplan erhalten und die Kosten gleich sind (jeweils 50%).
quelle