인덱싱된 뷰의 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가 매우 작다는 것을 알 수 있습니다.