为什么 CREATE INDEX ... WITH ONLINE=ON 会在几分钟内阻止对表的访问?

Han*_*non 30 index sql-server sql-server-2012

我有一个现有的表:

CREATE TABLE dbo.ProofDetails
(
    ProofDetailsID int NOT NULL 
        CONSTRAINT PK_ProofDetails 
        PRIMARY KEY CLUSTERED IDENTITY(1,1)
    , ProofID int NULL
    , IDShownToUser int NULL
    , UserViewedDetails bit NOT NULL 
        CONSTRAINT DF_ProofDetails_UserViewedDetails 
        DEFAULT ((0))
);
Run Code Online (Sandbox Code Playgroud)

该表有 150,000,000 行。系统 24x7x365 全天候运行,因此没有定期发生的维护窗口。

我想向表中添加索引,并且使用 SQL Server 的企业版,我应该能够在不阻止对表的写访问的情况下做到这一点。我使用的命令是:

CREATE INDEX IX_ProofDetails_ProofID_Etc 
ON dbo.ProofDetails (ProofID, IDShownToUser)
INCLUDE (UserViewedDetails)
WITH (ONLINE=ON
    , ALLOW_ROW_LOCKS=ON
    , ALLOW_PAGE_LOCKS=ON
    , FILLFACTOR=100
    , MAXDOP=4
);
Run Code Online (Sandbox Code Playgroud)

我在 SSMS 中通过按 自行执行了该语句F5。它运行了超过一分钟,然后开始阻塞其他会话。然后我立即取消了该CREATE INDEX命令,因为我无法阻止其他会话。

在第一分钟,没有任何东西阻止我的CREATE INDEX命令,sys.dm_exec_requests显示了等待类型CXPACKET- 当然。我认为这不是一件坏事,因为操作是并行化的。

我没有太多时间来检查sys.dm_exec_requests. 查询只返回了一行WHERE session_id = xxx。被阻止的会话试图将行插入到目标表中。

我不知道锁持续了多久,只是说我在语句开始后大约 2 分钟取消了执行。那时,阻塞发生了大约一分钟。

我误解了 的实施WITH (ONLINE=ON)吗?或者还有什么我需要注意的吗?

该服务器是一台相当强大的机器,配备 2 个四核 Xeon E5-2643 3.3Ghz 处理器、192GB RAM 和 5,000+ iops 的 SAN 存储。CPU 通常低于 20%,RAM 使用率为 93%,主要由 SQL Server 使用。盒子上没有其他任何东西在运行,只有 Windows Server 2012 和 SQL Server 2012。

ste*_*ary 34

使用online=on创建索引时,创建索引过程不会在创建索引对象本身时阻塞,但是当接近进程结束时,它会获取一段时间的模式修改锁*,以便实际将索引添加到表中,此锁类型将阻塞所有外部操作,直到释放锁,这可能会导致您的阻塞问题。

*Sch-M在线构建新的非聚集索引不需要锁,但在所有其他情况下都需要锁。新的非聚集索引在最后阶段只需要一个表级共享锁,与准备阶段所需的相同。

有关详细信息,请参阅此白皮书:

SQL Server 2005 中的联机索引操作

正如Mushtaq Mohammed在对该问题的评论中所建议的,另请参阅:

独角兽,彩虹,和联机索引操作保罗·兰德尔