Risoluzione delle viste

In Query Processor di SQL Server le viste indicizzate e non indicizzate vengono gestite in modi diversi:

  • Le righe di una vista indicizzata vengono archiviate nel database con lo stesso formato di una tabella. Se Query Optimizer decide di utilizzare una vista indicizzata in un piano di query, la vista indicizzata verrà gestita come una tabella di base.

  • Viene archiviata solo la definizione di una vista indicizzata e non le righe della vista. Query Optimizer incorpora la logica della definizione della vista nel piano di esecuzione compilato per l'istruzione SQL che fa riferimento alla vista non indicizzata.

La logica utilizzata da Query Optimizer di SQL Server per decidere quando utilizzare una vista indicizzata è analoga alla logica utilizzata per decidere quando utilizzare un indice per una tabella. Se i dati della vista indicizzata coprono tutta o parte dell'istruzione SQL e Query Optimizer identifica un indice della vista come percorso di accesso più economico, tale indice verrà scelto indipendentemente dal fatto che nella query venga fatto o meno riferimento alla vista in questione. Per ulteriori informazioni, vedere Risoluzione di indici nelle viste.

Se un'istruzione SQL fa riferimento a una vista non indicizzata, il parser e Query Optimizer analizzano le origini dell'istruzione SQL e della vista e le risolvono in un singolo piano di esecuzione. Il piano di esecuzione è lo stesso per l'istruzione SQL e per la vista.

Si consideri, ad esempio, la vista seguente:

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

In base a questa vista le due istruzioni SQL seguenti eseguono le stesse operazioni sulle tabelle di base e producono gli stessi risultati:

/* 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';

La caratteristica Showplan di SQL Server Management Studio indica che il motore relazionale compila lo stesso piano di esecuzione per entrambe le istruzioni SELECT.

Utilizzo di hint con le viste

Gli hint inseriti nelle viste di una query possono entrare in conflitto con altri hint individuati quando la vista viene espansa in modo da accedere alle relative tabelle di base. In tali circostanze la query restituisce un errore. Si consideri, ad esempio, la vista seguente nella cui definizione è contenuto un hint di tabella:

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;

Si supponga a questo punto di immettere la query seguente:

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

La query ha esito negativo perché l'hint SERIALIZABLE applicato nella vista Person.AddrState della query viene propagato a entrambe le tabelle Person.Address e Person.StateProvince quando la vista viene espansa. L'espansione della vista consente inoltre di rilevare l'hint NOLOCK nella tabella Person.Address. Gli hint SERIALIZABLE e NOLOCK sono in conflitto tra loro, pertanto la query risultante non è corretta.

Gli hint di tabella PAGLOCK, NOLOCK, ROWLOCK, TABLOCK o TABLOCKX sono in conflitto tra loro, così come HOLDLOCK, NOLOCK, READCOMMITTED, REPEATABLEREAD, SERIALIZABLE.

Gli hint possono propagarsi in più livelli di viste nidificate. Si supponga, ad esempio, una query che applica l'hint HOLDLOCK in una vista v1. Espandendo v1, si noterà che la definizione di tale vista include la vista v2, la cui definizione v2 include a sua volta un hint NOLOCK in una delle tabelle di base. Tale tabella eredita inoltre l'hint HOLDLOCK dalla query sulla vista v1. Gli hint NOLOCK e HOLDLOCK sono in conflitto tra loro, pertanto la query ha esito negativo.

Quando si utilizza l'hint FORCE ORDER in una query che contiene una vista, l'ordine di join delle tabelle all'interno della vista dipende dalla posizione della vista nel costrutto ordinato. La query seguente, ad esempio, consente di selezionare da tre tabelle e una vista:

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

La vista View1 viene definita come illustrato di seguito:

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

L'ordine di join nel piano di query sarà quindi Table1, Table2, TableA, TableB, Table3.