2009-07-03 377 views
0

我只是原型化一个新系统,用于推迟某些操作,直到某个数据库超时。我想出了(我认为)一个非常简单的模式。我第一次在SQL Server 2005 Express上进行原型设计,但是在2008 Developer上确认了同样的问题。我得到的错误是:SQL Server中的索引视图有问题,错误8646

消息8646,级别21,状态1,过程 取消,6号线无法找到索引ID 1指数 项,表 277576027的,在数据​​库 'XXXXXX' 。 指示索引已损坏或存在 与当前更新 计划有关的问题。运行DBCC CHECKDB或DBCC CHECKTABLE。如果问题仍然存在,请致电 联系产品支持。

我使用的模式是:

create schema Writeback authorization dbo 
    create table Deferrals (
     ClientID uniqueidentifier not null, 
     RequestedAt datetime not null, 
     CompletedAt datetime null, 
     CancelledAt datetime null, 
     ResolvedAt as ISNULL(CompletedAt,CancelledAt) persisted, 
     constraint PK_Writeback_Deferrals PRIMARY KEY (ClientID,RequestedAt) on [PRIMARY], 
     constraint CK_Writeback_Deferrals_NoTimeTravel CHECK ((RequestedAt <= CompletedAt) AND (RequestedAt <= CancelledAt)), 
     constraint CK_Writeback_Deferrals_NoSchrodinger CHECK ((CompletedAt is null) or (CancelledAt is null)) 
     /* TODO:FOREIGN KEY */ 
    ) 
    create view Pending with schemabinding as 
    select 
     ClientID 
    from 
     Writeback.Deferrals 
    where 
     ResolvedAt is null 
go 
alter table Writeback.Deferrals add constraint 
    DF_Writeback_Deferrals_RequestedAt DEFAULT CURRENT_TIMESTAMP for RequestedAt 
go 
create unique clustered index PK_Writeback_Pending on Writeback.Pending (ClientID) 
go 
create procedure Writeback.Defer 
    @ClientID uniqueidentifier 
as 
    set nocount on 

    insert into Writeback.Deferrals (ClientID) 
    select @ClientID 
    where not exists(select * from Writeback.Pending where ClientID = @ClientID) 
go 
create procedure Writeback.Cancel 
    @ClientID uniqueidentifier 
as 
    set nocount on 

    update 
     Writeback.Deferrals 
    set 
     CancelledAt = CURRENT_TIMESTAMP 
    where 
     ClientID = @ClientID and 
     CompletedAt is null and 
     CancelledAt is null 
go 
create procedure Writeback.Complete 
    @ClientID uniqueidentifier 
as 
    set nocount on 

    update 
     Writeback.Deferrals 
    set 
     CompletedAt = CURRENT_TIMESTAMP 
    where 
     ClientID = @ClientID and 
     CompletedAt is null and 
     CancelledAt is null 
go 

这引发了错误如下代码:

declare @ClientA uniqueidentifier 
declare @ClientB uniqueidentifier 
select @ClientA = newid(),@ClientB = newid() 

select * from Writeback.Pending 
exec Writeback.Defer @ClientA 
select * from Writeback.Pending 
exec Writeback.Defer @ClientB 
select * from Writeback.Pending 
exec Writeback.Cancel @ClientB --<-- Error being raised here 
select * from Writeback.Pending 
exec Writeback.Complete @ClientA 
select * from Writeback.Pending 
select * from Writeback.Deferrals 

我见过几个人遇到这样的问题,但他们似乎在他们的观点中有汇总(并且MS的消息表示他们将删除在2005 SP 1中创建此类索引视图的能力),或者他们通过在其联接子句中应用合并联接来解决此问题(但我没有一个)。

最初在Deferrals表中没有计算列,而视图中的where子句分别为NULL测试了CompletedAt和CancelledAt列。但我改变了上面的看法,只是为了看看我能否挑起不同的行为。

我所有的SET选项看起来都适合使用索引视图,如果它们不是,我希望抛出一个不太暴力的错误。

任何想法?

+0

正如我在对Mladen Prajdic的评论中指出的 - 我可以在新创建的数据库中运行上述脚本,但仍然会出现此错误。如果索引可能会快速损坏(在空表上创建2个插入),那么我会担心SQL Server的稳定性。另外,如上所述,我发现“其他”原因在网上提出这个消息,而且他们实际上并没有索引损坏。 – 2009-07-03 10:17:50

回答

0

我设法弄清楚是什么原因导致了这个错误,试图从头开始构建这个脚本,在我去的时候添加了部分内容。

如果视图是作为CREATE SCHEMA语句的一部分创建的,则会产生一些错误。如果我将CREATE SCHEMA分成它自己的批处理,然后分别创建表和视图,则一切正常。


早该编辑 - 我在Connect here上提出这个问题。它被确认为SQL Server 2008中的一个问题。

内部版本(在2010年)表示它已不再是问题,并且我(仅在2016年)确认该问题中的脚本不会生成在SQL Server 2012中出现同样的错误。该修复没有被移植到SQL Server 2008。

0

你有索引损坏。运行checkdb并查看它给你的错误。你可以做的最简单的事情就是重建索引。

如果它适用于你的sitution,也可以看看这个KB article

另请注意,将一个主键放在GUID列上会在其上创建一个聚集索引,这是您可以执行的最差性能表现。

+0

索引损坏 - 在10分钟前创建的数据库/模式/索引中,专门用于此原型? (另外,在新数据库中可重复使用) 另外,是的,了解使用GUID的各种问题。但这就是我在这个数据库中所坚持的。客户的实际指导实际上是用newsequentialid()生成的。目前不担心表现。 – 2009-07-03 09:57:00