连续处理时索引碎片

Chr*_*cci 10 sql-server-2005 sql-server fragmentation

SQL Server 2005

我需要能够在 900M 记录表中连续处理大约 350M 条记录。我用来选择要处理的记录的查询在我处理时变得严重碎片化,我需要停止处理以重建索引。伪数据模型&查询...

/**************************************/
CREATE TABLE [Table] 
(
    [PrimaryKeyId] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    [ForeignKeyId] [INT] NOT NULL,
    /* more columns ... */
    [DataType] [CHAR](1) NOT NULL,
    [DataStatus] [DATETIME] NULL,
    [ProcessDate] [DATETIME] NOT NULL,
    [ProcessThreadId] VARCHAR (100) NULL
);

CREATE NONCLUSTERED INDEX [Idx] ON [Table] 
(
    [DataType],
    [DataStatus],
    [ProcessDate],
    [ProcessThreadId]
);
/**************************************/

/**************************************/
WITH cte AS (
    SELECT TOP (@BatchSize) [PrimaryKeyId], [ProcessThreadId]
    FROM [Table] WITH ( ROWLOCK, UPDLOCK, READPAST )
    WHERE [DataType] = 'X'
    AND [DataStatus] IS NULL
    AND [ProcessDate] < DATEADD(m, -2, GETDATE()) -- older than 2 months
    AND [ProcessThreadId] IS NULL
)
UPDATE cte
SET [ProcessThreadId] = @ProcessThreadId;

SELECT * FROM [Table] WITH ( NOLOCK )
WHERE [ProcessThreadId] = @ProcessThreadId;
/**************************************/
Run Code Online (Sandbox Code Playgroud)

数据内容...
当列 [DataType] 被键入为 CHAR(1) 时,大约 35% 的所有记录等于 'X',其余记录等于 'A'。
只有 [DataType] 等于 'X' 的记录中,大约 10% 的 [DataStatus] 值将是 NOT NULL。

[ProcessDate] 和 [ProcessThreadId] 列将针对处理的每个记录进行更新。
[DataType] 列在大约 10% 的时间内更新('X' 更改为 'A')。
[DataStatus] 列的更新时间少于 1%。

现在我的解决方案是选择所有记录的主键进行处理到一个单独的处理表中。我在处理它们时删除键,以便作为索引片段处理更少的记录。

但是,这不适合我想要的工作流程,以便连续处理这些数据,无需人工干预和大量停机时间。我确实预计每季度都会因家务琐事而停机。但是现在,如果没有单独的处理表,我什至无法处理一半的数据集,而碎片变得严重到需要停止和重建索引。

关于索引或不同数据模型的任何建议?是否有我需要研究的模式?
我完全控制了数据模型和过程软件,所以没有什么是不可能的。

JNK*_*JNK 3

我首先将ProcessDateProcessthreadid字段移至另一个表。

现在,您从这个相当广泛的索引中选择的每一行也需要更新。

如果将这两个字段移至另一个表,主表上的更新量将减少 90%,这应该可以解决大部分碎片问题。

新表中仍然会有碎片,但在数据较少的较窄表上进行管理会更容易。