非标识列上的聚簇索引可加快批量插入?

时间:2010-09-17 08:26:36

标签: sql-server database sql-server-2008 clustered-index identity-column

我的两个问题是:

  • 我可以使用聚簇索引来加速 大表中的批量插入?
  • 然后我还能有效地使用吗? 外键关系,如果我的 IDENTITY列不是群集 指数了吗?

详细说明,我有一个包含公司数据的几个非常大(在100-1000万行之间)的数据库。通常,在这样的表中存在大约20-40个公司的数据,每个公司都是由“CompanyIdentifier”(INT)标记的他们自己的“块”。此外,每家公司都有大约20个部门,每个部门都有自己的“子部门”,标有“部门标识”(INT)。

经常发生从表中添加或删除整个“块”或“子块”。我的第一个想法是在这些块上使用表分区,但由于我使用的是SQL Server 2008标准版,因此我无权使用它。尽管如此,我所拥有的大多数查询都是在“块”或“子块”上执行而不是在整个桌面上执行。

我一直在努力为以下功能优化这些表:

  1. 在子块上运行的查询
  2. “基准测试”整个表格上运行的查询
  3. 插入/删除大块数据。
  4. 对于1)和2)我没有遇到很多问题。我在关键字段上创建了几个索引(也包含有用的CompanyIdentifier和DepartmentIdentifier),查询运行正常。

    但对于3)我一直在努力寻找一个好的解决方案。 我的第一个策略是始终禁用索引,批量插入大块并重建索引。这在开始时非常快,但现在数据库中有很多公司,每次重建索引需要很长时间。

    目前我的策略已经改为在插入时保持索引,因为现在看起来似乎更快了。但我想进一步优化插入速度。

    我似乎注意到,通过添加在CompanyIdentifier + DepartmentIdentifier上定义的聚簇索引,将新“块”加载到表中的速度更快。在我放弃这个策略以支持在IDENTITY列上添加聚簇索引之前,有几篇文章向我指出聚簇索引包含在所有其他索引中,因此聚簇索引应该尽可能小。但现在我正在考虑恢复这个旧策略来加速插入。我的问题,这是明智的,还是会在其他领域遇到性能打击?这会真的加速我的插入还是仅仅是我的想象力?

    我也不确定在我的情况下是否确实需要IDENTITY列。我希望能够与其他表建立外键关系,但我是否也可以使用类似于CompanyIdentifier + DepartmentIdentifier + [uniquifier]方案的东西?或者它必须是一个表格范围内,碎片化的IDENTITY号码?

    非常感谢任何建议或解释。

6 个答案:

答案 0 :(得分:3)

好吧,我已经对它进行了测试,并在两个“chunk-defined”列上放置了聚簇索引,从而提高了我的表的性能。

与我拥有集群IDENTITY密钥的情况相比,插入块现在相对较快,并且与我没有任何聚簇索引的情况一样快。删除块比使用或不使用聚簇索引更快。

我认为我想要删除或插入的所有记录都保证在硬盘的某个部分上一起使得表格更快 - 这对我来说似乎是合乎逻辑的。


更新:经过一年的设计经验,我可以说,对于这种工作方法,有必要安排定期重建所有索引(我们每周做一次)。否则,索引很快就会碎片化并且性能会丢失。尽管如此,我们正在迁移到具有分区表的新数据库设计,这在各方面都基本上更好 - 除了Enterprise Server许可证成本,但我们现在已经忘记了它。至少我有。

答案 1 :(得分:1)

聚簇索引是物理索引,物理数据结构,行顺序。如果插入聚簇索引的中间,则数据将物理插入当前数据的中间。在这种情况下,我想象一个严重的性能问题。我只从理论上知道这一点,因为如果我在实践中这样做,根据我的理论知识,这将是一个错误。

因此,我只在最终插入的字段上使用(并建议使用)聚簇索引,保留顺序。

聚集索引可以放在日期时间字段上,该字段标记插入的时刻或类似的东西,因为实际上它们将在追加一行后进行排序。身份也是一个很好的聚集索引,但并不总是与查询相关。

在你的解决方案中你放置了一个[uniquifier]字段,但是为什么这样做时你可以设置一个可以做到这一点的身份?它将是唯一的,物理上有序的,小的(对于其他表中的外键意味着更小的索引),并且在某些情况下更快。

难道你不能尝试这个,实验吗?我在这里有类似的情况,我有40亿行,不断插入更多(每秒高达100),表没有主键,也没有聚簇索引,因此本主题中的命题对我来说也非常有趣。

答案 2 :(得分:1)

  

我可以使用聚簇索引来加速大表中的批量插入吗?

从不!想象一下,你需要在该表中放置另外一百万行并让它们进行实际排序,从长远来看,这是一个巨大的性能损失。

  

如果我的IDENTITY列不再是聚集索引,我还能有效地使用外键关系吗?

绝对。顺便说一句,聚集索引不是银弹,可能比普通索引慢。

答案 3 :(得分:1)

查看System.Data.SqlClient.SqlBulkCopy API。鉴于您要求在数据库内外写入大量行,这可能是您需要的?

批量复制在单个操作中将数据流式传输到表中,然后执行一次索引检查。我使用它来复制500,000行进出数据库表,并且它的性能比我尝试过的任何其他技术都好一个数量级,假设您的应用程序可以构建为使用API​​?

答案 4 :(得分:0)

我一直在玩最后一点点的etl东西。我经历了jsut定期插入表,然后删除和读取插入前后的索引,尝试合并语句,然后我终于尝试了ssis。我卖的是ssis。就在昨天,我设法从每次运行约1-1个半小时到约24分钟切割一个etl过程(约2400万条记录,约6gb),让ssis处理插入物。

我相信使用高级服务你应该能够使用ssis。

答案 5 :(得分:0)