索引视图上的 DBCC 错误疑难解答

可以使用 DBCC CHECKDB 和 DBCC CHECKTABLE 查看索引视图是否包含与通过计算来自基表的视图找到的行相同的行。如果 DBCC 返回错误 8907 或 8908,则指示存储视图与计算视图不同,此时请从以下方面考虑来解决问题。

您的视图定义包含提示吗?

在 SQL Server 2000 中,可以创建包含表提示(如 NOLOCK)的索引视图。有时,这可能会导致索引视图损坏。如果视图中包含表提示,请删除该视图,编辑其定义以删除这些提示,然后重新创建该视图。然后,重新对该视图创建索引。

索引视图对 float 或 real 类型的值计算 SUM 聚合吗?

如果是,那么这是聚合列中索引视图和计算视图之间的唯一差异吗,并且对于对应的存储行和计算行来说差异小吗?如果差异不显著,考虑到数据和应用程序,则无需执行纠正操作。

如果差异显著,请删除视图的索引,然后重新创建索引。这种情况下出现损坏可能是由于浮点运算的近似性特点导致的。在维护索引视图期间添加数字的顺序有时可能会对最终结果有一点影响。有关如何使用近似数据类型的详细信息,请参阅使用 decimal、float 和 real 数据。如果应用程序使用浮点类型,但是只要使用十进制类型(numeric、money 或 decimal)便可满足您的要求,则请考虑在索引视图的修订版本中改为使用 numeric。

如果索引视图不包含对 float 或 real 类型值的聚合,并且收到错误 8907 或 8708,则请删除视图的索引,然后重新创建索引。

请勿使用 ALTER INDEX REBUILD 尝试消除存储视图和计算视图之间的差异,因为 ALTER INDEX REBUILD 在重新生成索引前不会重新计算视图。

对视图重新创建索引后,在视图上运行 DBCC CHECKTABLE 以验证不存在差异。如果仍存在差异,原因可能在于硬件问题或其他问题。

如何确定索引视图和计算视图之间的差异是否显著?

如果索引视图和计算视图之间的差异不是 float 或 real 值的 SUM 聚合中的小差异,则差异可能很显著。在这些情况下,应删除视图的索引,然后重新创建索引。如果视图之间的差异只存在于对 float 或 real 值的 SUM 操作中,并且视图较小,则从视觉上比较索引视图和计算视图,以确定差异是否显著。对于视图 ViewName,按照如下所示获取计算值和存储值:

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

您会发现在聚合视图中查看相同组的不相等行的绝对差异或百分比差异很有用,能够帮助您确定差异是否显著。例如,以下脚本显示了如何比较有些许差异的索引视图和计算视图。此脚本显示了同一组中具有不同的存储总和与计算总和的几对行。

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

结果显示只有一组具有不同的 SUM 值,并且差异 sum_b_diff 非常小。