视图解析
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 显示计划功能显示关系引擎为这两个 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。