Risoluzione degli errori DBCC nelle viste indicizzate

È possibile utilizzare DBCC CHECKDB e DBCC CHECKTABLE per controllare se una vista indicizzata contiene le stesse righe che si ottengono calcolando la vista dalle tabelle di base. Se DBCC restituisce l'errore 8907 o 8908, i quali indicano che la vista archiviata non è identica alla vista calcolata, provare le seguenti soluzioni per risolvere il problema.

La vista contiene hint?

In SQL Server 2000 è possibile creare viste indicizzate contenenti hint di tabella, ad esempio NOLOCK. In alcune situazioni, ciò può provocare il danneggiamento della vista indicizzata. Se la vista contiene hint di tabella, eliminare la vista, modificarne la definizione per rimuovere gli hint e creare nuovamente la vista. Quindi, creare nuovamente l'indice sulla vista.

La vista indicizzata calcola un'aggregazione SUM su valori di tipo float o real?

In caso affermativo, le uniche differenze fra la vista indicizzata e la vista calcolata si trovano nella colonna aggregata e le differenze fra le righe archiviate e quelle calcolate sono di lieve entità? Se, considerando i dati e l'applicazione, le differenze non sono significative, non sono necessari interventi di correzione.

Se le differenze sono significative, eliminare l'indice della vista e crearlo nuovamente. In questo caso il danneggiamento è probabilmente provocato dalla natura approssimativa dell'aritmetica a virgola mobile. L'ordine in cui vengono aggiunti i numeri durante la manutenzione delle viste indicizzate può a volte avere ripercussioni ridotte sul risultato finale. Per ulteriori informazioni sull'utilizzo dei tipi di dati approssimati, vedere Utilizzo dei tipi di dati decimal, float e real. Se l'applicazione utilizza tipi a virgola mobile, ma le esigenze dell'utente possono essere soddisfatte tramite l'utilizzo di decimali esatti (tipo numeric, money o decimal), in una versione aggiornata della vista indicizzata provare a utilizzare dati numeric.

Se la vista indicizzata non contiene un'aggregazione su valori di tipo float o real e viene generato l'errore 8907 o 8708, eliminare l'indice della vista e crearlo nuovamente.

Non utilizzare ALTER INDEX REBUILD per tentare di eliminare le differenze fra la vista archiviata e quella calcolata, perché ALTER INDEX REBUILD non ricalcola la vista prima di ricostruire l'indice.

Dopo aver ricreato l'indice sulla vista, eseguire DBCC CHECKTABLE sulla vista per verificare che non siano più presenti differenze. Se sono presenti differenze, considerare la possibilità di un errore hardware o di tipo diverso.

Come si può determinare se le differenze tra la vista indicizzata e la vista calcolata sono significative?

Se le differenze tra la vista indicizzata e la vista calcolata non sono limitate a piccole variazioni in un'aggregazione SUM di un valore float o real , è probabile che siano significative. In questi casi, è consigliabile eliminare l'indice sulla vista e ricrearlo. Se l'unica differenza tra le viste è in un'aggregazione SUM su un valore float o real e la vista è di piccole dimensioni, confrontare visivamente la vista indicizzata e la vista calcolata e stabilire se le differenze sono significative. Per ottenere i valori calcolati e archiviati di una vista ViewName, procedere come segue:

SELECT * FROM ViewName OPTION(EXPAND VIEWS) -- Get calculated view.
SELECT * FROM ViewName WITH(NOEXPAND)       -- Get stored view.

Per determinare se le differenze siano significative, può risultare utile esaminare la differenza assoluta o percentuale per le righe diverse dello stesso gruppo in una vista aggregata. Ad esempio, lo script seguente illustra come confrontare una vista indicizzata e una vista calcolata che differiscono lievemente. Nello script vengono visualizzate coppie di righe dello stesso gruppo caratterizzate da somme archiviate e somme calcolate diverse.

IF OBJECT_ID('v') IS NOT NULL DROP VIEW v
IF OBJECT_ID('t') IS NOT NULL DROP TABLE t
go
CREATE TABLE t
   (id int NOT NULL PRIMARY KEY, 
    a int NOT NULL, 
    b float(53) NOT NULL)
GO
CREATE VIEW v WITH SCHEMABINDING AS
SELECT a, SUM(b) AS sum_b, COUNT_BIG(*) AS c
FROM dbo.t
GROUP BY a
GO
CREATE UNIQUE CLUSTERED INDEX idx ON v(a)
GO
INSERT t VALUES(1, 1,1.0e1)
INSERT t VALUES(2, 1,1.0e2)
INSERT t VALUES(3, 2, 1.0e0)
INSERT t VALUES(4, 2, 5.0e-17)
INSERT t VALUES(5, 2, 5.0e-17)
INSERT t VALUES(6, 2, 5.0e-17)
GO
DELETE FROM t WHERE id=3
GO
DBCC CHECKTABLE ('v')
GO
-- Show the groups that have different SUMs, 
-- and the difference between the sums.
SELECT *, v1.sum_b - v2.sum_b AS sum_b_diff
FROM (SELECT * FROM v WITH (NOEXPAND)) AS v1,
     (SELECT * FROM v) AS v2
WHERE v1.a=v2.a
AND (v1.sum_b - v2.sum_b) <> 0
OPTION(EXPAND VIEWS)
GO

Il risultato evidenzia che un solo gruppo presenta un valore SUM diverso e che la differenza sum_b_diff è di minima entità.