Sichtauflösung
Der SQL Server-Abfrageprozessor behandelt indizierte und nicht indizierte Sichten unterschiedlich:
Die Zeilen einer indizierten Sicht werden in der Datenbank in demselben Format wie eine Tabelle gespeichert. Wenn sich der Abfrageoptimierer entscheidet, eine indizierte Sicht in einem Abfrageplan zu verwenden, wird die indizierte Sicht auf die gleiche Weise wie eine Basistabelle behandelt.
Nur die Definition einer nicht indizierten Sicht wird gespeichert, nicht die Zeilen der Sicht. Der Abfrageoptimierer nimmt die Logik aus der Sichtdefinition in den Ausführungsplan auf, den er für die SQL-Anweisung erstellt, die auf die nicht indizierte Sicht verweist.
Die Logik, anhand derer der SQL Server-Abfrageoptimierer entscheidet, wann eine indizierte Sicht verwendet werden soll, ist mit der Logik vergleichbar, anhand derer ermittelt wird, wann ein Index für eine Tabelle verwendet wird. Wenn die Daten in der indizierten Sicht die gesamte oder einen Teil der SQL-Anweisung erfüllen und der Abfrageoptimierer ermittelt, dass ein Index für die Sicht der Zugriffspfad mit den geringsten Kosten ist, wählt der Abfrageoptimierer den Index unabhängig davon aus, ob im Namen der Abfrage auf die Sicht verwiesen wird. Weitere Informationen finden Sie unter Auflösen von Indizes für Sichten.
Wenn eine SQL-Anweisung auf eine nicht indizierte Sicht verweist, analysieren der Parser und der Abfrageoptimierer die Quelle sowohl der SQL-Anweisung als auch der Sicht und lösen sie dann zu einem einzigen Ausführungsplan auf. Es gibt nicht einen Plan für die SQL-Anweisung und einen weiteren Plan für die Sicht.
Nehmen Sie z. B. an, dass die folgende Sicht verwendet wird:
USE AdventureWorks2008R2;
GO
CREATE VIEW EmployeeName AS
SELECT h.BusinessEntityID, p.LastName, p.FirstName
FROM HumanResources.Employee AS h
JOIN Person.Person AS p
ON h.BusinessEntityID = p.BusinessEntityID;
GO
Von dieser Sicht ausgehend führen die beiden folgenden SQL-Anweisungen die gleichen Vorgänge für die Basistabellen aus und erzeugen identische Ergebnisse:
/* SELECT referencing the EmployeeName view. */
SELECT LastName AS EmployeeLastName, SalesOrderID, OrderDate
FROM AdventureWorks2008R2.Sales.SalesOrderHeader AS soh
JOIN AdventureWorks2008R2.dbo.EmployeeName AS EmpN
ON (soh.SalesPersonID = EmpN.BusinessEntityID)
WHERE OrderDate > '20020531';
/* SELECT referencing the Person and Employee tables directly. */
SELECT LastName AS EmployeeLastName, SalesOrderID, OrderDate
FROM AdventureWorks2008R2.HumanResources.Employee AS e
JOIN AdventureWorks2008R2.Sales.SalesOrderHeader AS soh
ON soh.SalesPersonID = e.BusinessEntityID
JOIN AdventureWorks2008R2.Person.Person AS p
ON e.BusinessEntityID =p.BusinessEntityID
WHERE OrderDate > '20020531';
Durch die SQL Server Management Studio-Showplanfunktion wird deutlich, dass das relationale Modul für beide SELECT-Anweisungen denselben Ausführungsplan erstellt.
Verwenden von Hinweisen mit Sichten
Hinweise, die für Sichten in einer Abfrage gespeichert werden, können zu Konflikten mit anderen Hinweisen führen, die beim Erweitern der Sicht für den Zugriff auf ihre Basistabellen erkannt werden. Wenn dieser Fall eintritt, gibt die Abfrage einen Fehler zurück. Angenommen, die folgende Sicht enthält einen Tabellenhinweis in ihrer Definition:
USE AdventureWorks2008R2;
GO
CREATE VIEW Person.AddrState WITH SCHEMABINDING AS
SELECT a.AddressID, a.AddressLine1,
s.StateProvinceCode, s.CountryRegionCode
FROM Person.Address a WITH (NOLOCK), Person.StateProvince s
WHERE a.StateProvinceID = s.StateProvinceID;
Nehmen Sie nun an, dass die folgende Abfrage eingegeben wird:
SELECT AddressID, AddressLine1, StateProvinceCode, CountryRegionCode
FROM Person.AddrState WITH (SERIALIZABLE)
WHERE StateProvinceCode = 'WA';
Die Abfrage erzeugt einen Fehler, weil der SERIALIZABLE-Hinweis, der für die Person.AddrState-Sicht in der Abfrage angewendet wird, an die beiden Tabellen Person.Address und Person.StateProvince in der Sicht weitergegeben wird, wenn diese erweitert wird. Das Erweitern der Sicht legt jedoch außerdem den NOLOCK-Hinweis für Person.Address offen. Da die SERIALIZABLE- und NOLOCK-Hinweise einen Konflikt verursachen, ist die sich ergebende Abfrage falsch.
Die PAGLOCK-, NOLOCK-, ROWLOCK-, TABLOCK- und TABLOCKX-Tabellenhinweise stehen miteinander in Konflikt, ebenso wie die HOLDLOCK-, NOLOCK-, READCOMMITTED-, REPEATABLEREAD- und SERIALIZABLE-Tabellenhinweise.
Hinweise können über die Ebenen geschachtelter Sichten weitergegeben werden. Angenommen, eine Abfrage wendet den HOLDLOCK-Hinweis auf eine Sicht v1 an. Wenn v1 erweitert wird, wird erkennbar, dass die Sicht v2 Teil ihrer Definition ist. Die Definition von v2 enthält einen NOLOCK-Hinweis für eine der Basistabellen der Sicht. Diese Tabelle erbt jedoch außerdem den HOLDLOCK-Hinweis für Sicht v1 von der Abfrage. Da die NOLOCK- und HOLDLOCK-Hinweise einen Konflikt verursachen, führt die Abfrage zu einem Fehler.
Wenn der FORCE ORDER-Hinweis in einer Abfrage verwendet wird, die eine Sicht enthält, wird die Joinreihenfolge der Tabellen innerhalb der Sicht durch die Position der Sicht im sortierten Konstrukt festgelegt. Die folgende Abfrage trifft z. B. eine Auswahl aus drei Tabellen und einer Sicht:
SELECT * FROM Table1, Table2, View1, Table3
WHERE Table1.Col1 = Table2.Col1
AND Table2.Col1 = View1.Col1
AND View1.Col2 = Table3.Col2;
OPTION (FORCE ORDER)
Außerdem ist View1 wie im folgenden Beispiel gezeigt definiert:
CREATE VIEW View1 AS
SELECT Colx, Coly FROM TableA, TableB
WHERE TableA.ColZ = TableB.Colz;
Die Joinreihenfolge im Abfrageplan lautet Table1, Table2, TableA, TableB, Table3.