每天我使用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
答案 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之间切换,你很高兴....