SQL Server 2008索引碎片问题

时间:2011-08-20 18:26:10

标签: sql sql-server-2008 indexing

每天我使用BULK INSERT从一些文本文件导入2,000,000行到SQL Server 2008中,然后我做一些后处理来更新记录。

我在表上有一些索引可以尽快执行后期处理,在正常情况下,后处理脚本大约需要40秒才能运行。

但有时(我不知道何时)后处理不起作用。在我提到过的情况下,一小时后就没有了!在重建索引之后,一切都很好而且正常。

我该怎么做才能防止问题发生?

现在,我每晚都有重建所有索引的工作。为什么索引碎片增长到90%?

更新: 这是我的表格,我将文本文件导入:

  CREATE TABLE [dbo].[My_Transactions](
    [My_TransactionId] [bigint] NOT NULL,
    [FileId] [int] NOT NULL,
    [RowNo] [int] NOT NULL,
    [TransactionTypeId] [smallint] NOT NULL,
    [TransactionDate] [datetime] NOT NULL,
    [TransactionNumber] [dbo].[TransactionNumber] NOT NULL,
    [CardNumber] [dbo].[CardNumber] NULL,
    [AccountNumber] [dbo].[CardNumber] NULL,
    [BankCardTypeId] [smallint] NOT NULL,
    [AcqBankId] [smallint] NOT NULL,
    [DeviceNumber] [dbo].[DeviceNumber] NOT NULL,
    [Amount] [dbo].[Amount] NOT NULL,
    [DeviceTypeId] [smallint] NOT NULL,
    [TransactionFee] [dbo].[Amount] NOT NULL,
    [AcqSwitchId] [tinyint] NOT NULL
) ON [PRIMARY]

GO

CREATE NONCLUSTERED INDEX [_dta_index_Jam_Transactions_8_1290487676__K1_K4_K12_K6_K11_5] ON [dbo].[Jam_Transactions] 
(
    [Jam_TransactionId] ASC,
    [TransactionTypeId] ASC,
    [Amount] ASC,
    [TransactionNumber] ASC,
    [DeviceNumber] ASC
)
INCLUDE ( [TransactionDate]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [_dta_index_Jam_Transactions_8_1290487676__K12_K6_K11_K1_5] ON [dbo].[Jam_Transactions] 
(
    [Amount] ASC,
    [TransactionNumber] ASC,
    [DeviceNumber] ASC,
    [Jam_TransactionId] ASC
)
INCLUDE ( [TransactionDate]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_Jam_Transactions] ON [dbo].[Jam_Transactions] 
(
    [Jam_TransactionId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

4 个答案:

答案 0 :(得分:2)

您是否尝试过这么大的插入后刷新统计信息:

UPDATE STATISTICS my_table

我对大量批量插入的经验是,统计数据全部被破坏,之后需要刷新,它也比运行REINDEX或索引REORDER快得多。

另一个选择是查看填充索引,您的索引上可能没有填充填充因子,这意味着如果您的索引是:

A, B, D, E, F

并插入一个C CardNumber的值,然后您的索引将如下所示:

A, B, D, E, F, C

因此,如果您指定15%的索引的填充因子,我们会看到它看起来像粗略的,因此约为20%的碎片:

A, B, D, _, E, F

(注意内部空格大致放在fillfactor%的中间点而不是最后)

因此,当您插入C值时,它更接近正确,但它实际上看到D刚刚与C交换,并且通常在该点移动D.

除此之外,你确定碎片实际上是问题,因为重新索引表的一部分被读取并完全加载到内存中(假设它适合),因此你在其上运行的任何查询都会非常快。

答案 1 :(得分:1)

为什么不在夜间工作中包含这个表,为什么不在BULK INSERT和任何'后处理'之间进行索引维护(在此表中具体)是夜间导入作业的一部分?< / p>

我们没有足够的信息来了解为什么索引碎片快速增长。哪个指数?有多少指数?文件中数据的顺序是什么?

您还可以考虑使用ORDER语句中的BULK INSERT选项来更改数据的插入方式。它可能会使负载需要更长时间,但它应该减少重新组织的需要。同样取决于源数据的顺序和成为碎片的索引。

最后,重建/不重建或重组/不重组索引的影响是什么?你试过两个吗?也许它会使您在重建时更快地运行后处理,但也许只需要进行碎片整理。虽然它可以使后期处理更快,但是当天晚些时候针对该表运行的查询呢?你有没有针对这些指标做任何指标,看他们是否加速或减速取决于你晚上做什么?

答案 2 :(得分:0)

您的主表每天是否会继续增长200万行,还是会发生大量删除?您是否可以批量插入临时导入表并在插入主表之前进行处理?您始终可以使用提示强制查询使用某些索引:

SELECT *
FROM your_table_name WITH (INDEX(your_index_name))
WHERE your_column_name = 5

答案 3 :(得分:0)

我会尝试在批量行插入之前使索引脱机,并在批量行插入后将其重新联机。与重新索引或执行丢弃和创建索引相比,更快,更快速...区别在于索引是否存储数据但索引当前未被使用,“离线”直到它为止带回“在线”。我有一个150万行插入过程,并且我的一个非聚集索引碎片出现问题导致性能不佳。使用MSSQL离线在线索引选项将99%的碎片形成为.14%....

代码示例:

ALTER INDEX idx_a ON dbo.tbl_A
REBUILD WITH (ONLINE = OFF);

在OFF和ON之间切换,你很高兴....