檢視解析

SQL Server 查詢處理器對待索引及非索引檢視的方式不同:

  • 索引檢視的資料列是儲存在資料表庫中,並使用與資料表相同的格式。如果查詢最佳化工具決定使用查詢計畫中的索引檢視,將以處理基底資料表的相同方式來處理索引檢視。

  • 只會儲存非索引檢視的定義,而不會儲存檢視的資料列。查詢最佳化工具會將檢視定義中的邏輯,合併到它為參考非索引檢視之 SQL 陳述式所建立的執行計畫中。

SQL Server 查詢最佳化工具用來決定何時使用索引檢視的邏輯,類似於用以決定何時使用資料表中索引的邏輯。如果索引檢視中的資料涵蓋了全部或部分的 SQL 陳述式,並且查詢最佳化工具判斷出檢視中的索引是低成本的存取路徑,那麼查詢最佳化工具便會選擇該索引,而不論查詢中是否有依名稱參考此檢視。如需詳細資訊,請參閱<解析檢視上的索引>。

當 SQL 陳述式參考無索引的檢視時,剖析器與查詢最佳化工具會分析 SQL 陳述式和檢視的來源,然後將它們解析成單一執行計畫。SQL 陳述式與檢視不會分屬於不同的計畫。

例如,請考慮下列檢視:

USE AdventureWorks;
GO
CREATE VIEW EmployeeName AS
SELECT h.EmployeeID, c.LastName, c.FirstName
FROM HumanResources.Employee AS h 
JOIN Person.Contact AS c
ON h.ContactID = c.ContactID;
GO

在此檢視中,這兩個 SQL 陳述式會在基底資料表上執行相同的作業,並產生相同的結果:

/* SELECT referencing the EmployeeName view. */
SELECT LastName AS EmployeeLastName, SalesOrderID, OrderDate
FROM AdventureWorks.Sales.SalesOrderHeader AS soh
JOIN AdventureWorks.dbo.EmployeeName AS EmpN
ON (soh.ContactID = EmpN.EmployeeID)
WHERE OrderDate > '20020531';

/* SELECT referencing the Contact and Employee tables directly. */
SELECT LastName AS EmployeeLastName, SalesOrderID, OrderDate
FROM AdventureWorks.HumanResources.Employee AS e 
JOIN AdventureWorks.Sales.SalesOrderHeader AS soh
ON soh.SalesPersonID = e.EmployeeID
JOIN AdventureWorks.Person.Contact AS c
ON e.ContactID =c.ContactID
WHERE OrderDate > '20020531';

SQL Server Management Studio Showplan 功能,顯示出關聯式引擎為這兩個 SELECT 陳述式建立相同的執行計畫。

使用檢視的提示

在查詢中檢視所放置的提示可能與在擴充檢視以存取基底資料表時所發現的其他提示衝突。當此發生時,查詢會傳回錯誤:例如,請考慮下列在其定義中包含資料表提示的檢視:

USE AdventureWorks;
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;

現在假設您輸入以下查詢:

SELECT AddressID, AddressLine1, StateProvinceCode, CountryRegionCode
FROM Person.AddrState WITH (SERIALIZABLE)
WHERE StateProvinceCode = 'WA';

查詢會失敗,因為在查詢中的 Person.AddrState 檢視所套用的 SERIALIZABLE 提示,會在檢視展開時傳播至檢視中的 Person.Address 與 Person.StateProvince 資料表中。不過,展開檢視也會顯示在 Person.Address 上的 NOLOCK 提示。因為 SERIALIZABLE 與 NOLOCK 提示有衝突,所以產生的查詢不正確。

PAGLOCK、NOLOCK、ROWLOCK、TABLOCK 或 TABLOCKX 資料表提示彼此之間會發生衝突,HOLDLOCK、NOLOCK、READCOMMITTED、REPEATABLEREAD、SERIALIZABLE 資料表提示彼此之間也是一樣。

提示可以透過巢狀檢視層級來傳播。例如,假設查詢在 v1 檢視中套用 HOLDLOCK 提示。展開 v1 時,發現 v2 檢視是其定義的一部份。v2 的定義包括其中一個基底資料表上的 NOLOCK 提示。但是此資料表也會繼承在 v1 檢視中查詢的 HOLDLOCK 提示。因為 NOLOCK 與 HOLDLOCK 提示有衝突,所以查詢會失敗。

當在包含檢視的查詢中使用 FORCE ORDER 提示時,在檢視中資料表的聯結順序將由依序建構中的檢視位置來決定。例如,下列查詢會從三個資料表和一個檢視中選取:

SELECT * FROM Table1, Table2, View1, Table3
WHERE Table1.Col1 = Table2.Col1 
    AND Table2.Col1 = View1.Col1
    AND View1.Col2 = Table3.Col2;
OPTION (FORCE ORDER)

而 View1 的定義如下所示:

CREATE VIEW View1 AS
SELECT Colx, Coly FROM TableA, TableB
WHERE TableA.ColZ = TableB.Colz;

查詢計劃中的聯結順序為 Table1、 Table2、TableA、TableB、Table3。