提高SQL Server上索引重建的速度


9

我正在将大量数据导入到一个空数据库中,在开始之前,我禁用了所有非唯一的非聚集索引,以查看是否可以改善导入性能。

现在我想重新启用索引,我想知道是否有什么我可以做的来优化它。

有超过100个表和将近2,000个索引要重建。该数据库的大小为200GB。

我正在运行的脚本的关键部分是:

declare c_toggle_index cursor FORWARD_ONLY READ_ONLY for
    select  'alter index ' + QUOTENAME(i.name) + ' on ' + o.name + ' rebuild'
    from    sys.indexes as i
    Inner Join sys.objects o
    On o.object_id = i.object_id
    Where o.is_ms_shipped = 0
    And i.index_id >= 1
    and i.type > 1
    and i.is_disabled = 1

我考虑为alter index语句设置ONLINE = OFF,但是随着索引开始禁用,我不确定该设置是否会起作用。我还考虑过将SORT_IN_TEMPDB = ON设置,但是由于tempdb文件与数据库的.mdf文件位于同一驱动器上,因此我认为这样做也没有任何好处。

在运行重建脚本时,我注意到我有很多CXPACKET等待类型。我真的不明白为什么会这样,或者如果我要解决这个问题。

最后一点可能很重要:除了将数据导入数据库之外,我的整个服务器当前都处于非活动状态。没有其他要考虑或担心的用户活动;我唯一关心的是在尽可能短的时间内将数据导入数据库。


3
当您说的唯一问题是导入时间时,您是指从导入开始到重新启用索引结束之间的时间?如果是这样,您应该只在导入期间启用索引。对于200GB数据而言,2,000个索引听起来像很多索引。也许您应该查看索引使用DMV,以查看是否有一些可以删除。
Max Vernon

1
需要澄清的是,您需要重复执行相同的200GB导入,而不仅仅是一次?
乔恩·塞格尔

1
我只需要执行一次导入,但是作为在有限的时间范围内的较大流程的一部分,因此我目前正在测试该流程以使其适合该窗口。@MaxVernon看起来正确的是,使索引处于启用状态是最快的方法,尽管我很惊讶地发现禁用索引,导入数据然后重新启用索引通常更快。这是一个第三方数据库,因此删除索引或进行其他更改实际上是不可能的。
paulH 2013年

3
好的。关于CXPACKET等待:索引会自行重建扫描索引(甚至重建索引),这些扫描可以使用并行性。您不必担心这些等待-并行性可能会有所帮助。
乔恩·塞格尔

Answers:


10

在这种情况下,要实现最佳的导入性能,需要三件事:

  1. 最少记录的基表插入
  2. 最少记录的非聚集索引构建
  3. 避免物理阅读

最小记录

没有非聚集索引的情况下,将记录最少的插入到空聚集表需要:

  1. 使用SIMPLEBULK_LOGGED数据库恢复模型
  2. 指定表锁和有序的输入(例如TABLOCKORDER提示)

边注:

如果启用了跟踪标志610,也可以对具有非聚集索引的聚集表进行最少日志记录的插入。非聚集索引插入是否最少记录取决于查询优化器选择的查询计划。

如果查询计划对非聚簇索引使用一个单独的迭代器, 并且该迭代器的DMLRequestSort属性设置为true,则只要满足前面提到的其他条件,非聚簇索引的插入将被最少地记录。

分别构建非聚集索引

这样做的好处是:

  1. 可以在不启用TF 610的情况下最小化记录群集索引插入
  2. CREATE INDEX 如果恢复模型不是,则最少记录一次 FULL

避免物理阅读

理想情况下,要导入的数据将存储在单独的计算机上,或者至少存储在用于承载数据库的物理存储上。

数据库服务器应具有足够的内存以将最大的基本表保存在缓存中,并留有足够的空间用于构建非聚集索引时所需的排序操作。

一个好的模式是快速加载基表(最小记录的聚集索引负载),然后在仍缓存其数据页的同时为该表构建所有非聚集索引。

该问题概述了首先加载基本表,然后构建非聚集索引的过程。游标定义不使用ORDER BY子句至少将同一表上的非聚集索引构建分组在一起。

可能的结果是,不同表的数据页被重复读取到缓存中,然后由于以不确定的顺序建立非聚集索引而被丢弃

重复进行物理读取的成本完全支配了通过分别构建非集群索引而获得的最小日志记录的好处。这解释了为什么您发现使用现有索引加载表的速度更快(因为给定表的所有非聚集索引都将在移至下一个表之前得到维护)。

摘要

应该重新设计导入过程,以一次批量装入一张表。这意味着在继续下一个索引之前,先加载表并构建所有非聚集索引。SQL Server实例应具有足够的内存来容纳最大的表并同时执行最大的非聚集索引排序。

可以尝试在将数据加载到已具有非聚集索引的表中之前启用TF 610。通常这没有以前的方法快,但是可能足够快。

有关更多信息,请参见以下内容:

数据加载性能指南

可以最少记录的操作

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.