10

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

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命令已经执行了一个多小时。鉴于我没有尝试更改任何现有值,为什么要花这么长时间?

4

2 回答 2

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

请注意,在此示例中,表的大小或复杂性无关紧要;我被迫等待交易完成。Foo在我通过COMMIT事务或关闭会话 1释放锁定之前,我在会话 2 中的更改指令不会完成。

你怎么知道这是否是你的问题?查看 SSMS 活动监视器中的“进程”列表。如果您的ALTER指令正在等待其他操作完成,则“阻止者”列中将显示一个数字,指示导致您的问题的命令的会话 ID。

SSMS 进程列表显示被阻止的进程

该会话可能又在等待另一个会话,依此类推。1如果您遵循这些参考资料,您最终会在“Head Blocker”列中找到一个带有 a 的进程。从那里您可以决定适当的操作是终止有问题的进程,还是等待它结束。

于 2014-09-05T16:03:26.407 回答
0
  1. 重新创建具有所有约束的对象
  2. 转储数据
  3. 锁定原始对象
  4. 切换对象名称

如果您想像 Dan 提到的那样优化、重新索引和避免冲突,这种方式是最快的

于 2014-09-05T16:13:46.400 回答