为什么在现有列中添加可为空的默认约束需要这么长时间?

时间:2014-09-05 15:24:47

标签: sql sql-server-2012 default-constraint

我有一个大约有4亿行的现有表。该表包含一组名为IsModified,IsDeleted和IsExpired的bit列。

CREATE TABLE [dbo].[ActivityAccumulator](
    [ActivityAccumulator_SK] [int] IDENTITY(1,1) NOT NULL,
    [ActivityAccumulatorPK1] [int] NULL,
    [UserPK1] [int] NULL,
    [Data] [varchar](510) NULL,
    [CoursePK1] [int] NULL,
    [TimeStamp] [datetime] NULL,
    [SessionID] [int] NULL,
    [Status] [varchar](50) NULL,
    [EventType] [varchar](40) NULL,
    [DWCreated] [datetime] NULL,
    [DWModified] [datetime] NULL,
    [IsModified] [bit] NULL,
    [DWDeleted] [datetime] NULL,
    [IsDeleted] [bit] NULL,
    [ActivityAccumulatorKey] [bigint] NULL,
    [ContentPK1] [bigint] NULL
) ON [PRIMARY]

我想在表中添加一个默认约束,对于所有将来插入的行,将默认这些位列为0.我试图通过以下命令执行此操作:

ALTER TABLE ActivityAccumulator 
ADD CONSTRAINT DF_ActivityAccumulatorIsExpired DEFAULT (0) FOR IsExpired

ALTER TABLE ActivityAccumulator 
ADD CONSTRAINT DF_ActivityAccumulatorIsDeleted DEFAULT (0) FOR IsDeleted

ALTER TABLE ActivityAccumulator 
ADD CONSTRAINT DF_ActivityAccumulatorIsModified DEFAULT (0) FOR IsModified

我最终希望返回并清理现有数据,将零值放在NULL值的任何位置,但我现在不需要这样做。

只是尝试运行第一个ADD CONSTRAINT命令已经执行了一个多小时了。鉴于我不想改变任何现有的价值,为什么这需要这么长时间呢?

2 个答案:

答案 0 :(得分:5)

一种可能是您的服务器上有另一个锁定此表的进程。

想象一下,我打开了两个SSMS窗口,在第一个窗口中我执行了这些命令:

-- Session 1
CREATE TABLE Foo(IsTrue BIT) 
INSERT INTO Foo VALUES (1),(1),(0)
BEGIN TRANSACTION
UPDATE Foo SET IsTrue = 1 - IsTrue

然后打开SSMS窗口以使事务永远不会关闭,尝试在另一个SSMS会话中执行此简单约束命令将永远挂起:

-- Session 2
ALTER TABLE Foo ADD CONSTRAINT FooDefault DEFAULT(0) FOR IsTrue

请注意,在此示例中,表的大小或复杂性无关紧要;我被迫等待交易完成。我在会话2中的alter指令不会完成,直到Foo通过COMMIT交易或结束会话1释放ALTER锁定。

你怎么知道这是不是你的问题?看看"流程" SSMS活动监视器中的列表。如果您的1指令正在等待其他内容完成,那么" Blocked By"列,指示导致问题的命令的会话ID。

SSMS Process list showing blocked process

那个会话可能会等待另一个会议等等。如果您遵循这些参考,您最终会在" Head Blocker"中找到一个{{1}}的流程。柱。从那里你可以决定是否采取适当的行动来消除违规过程,或者只是等待它。

答案 1 :(得分:0)

  1. 使用所有约束重新创建对象
  2. 转储数据
  3. 锁定原始对象
  4. 切换对象名称
  5. 如果你想优化,重新索引和避免像Dan提到的那样的冲突,这种方式是最快的