8

我的两个问题是:

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

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

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

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

  1. 在子块上运行的查询
  2. 在整个表上运行的“基准测试”查询
  3. 插入/删除大块数据。

对于1)和2)我没有遇到很多问题。我已经在关键字段上创建了几个索引(还包含有用的 CompanyIdentifier 和 DepartmentIdentifier)并且查询运行良好。

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

目前,我的策略已更改为仅在插入时保持索引打开,因为现在这似乎更快。但我想进一步优化插入速度。

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

我也不确定在我的情况下是否真的需要一个 IDENTITY 列。我希望能够与其他表建立外键关系,但我也可以为此使用 CompanyIdentifier+DepartmentIdentifier+[uniquifier] 方案吗?或者它必须是一个表范围的、碎片化的 IDENTITY 编号?

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

4

6 回答 6

4

好吧,我已经对其进行了测试,在两个“块定义”列上放置一个聚集索引可以提高我的表的性能。

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

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


更新:经过一年的这种设计经验,我可以说,要使这种方法起作用,有必要安排定期重建所有索引(我们每周进行一次)。否则,索引很快就会变得碎片化并且性能下降。尽管如此,我们正在迁移到带有分区表的新数据库设计,这基本上在各方面都更好——除了企业服务器许可成本,但我们现在已经忘记了它。至少我有。

于 2010-09-29T21:34:40.303 回答
1

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

因此,我只在始终以物理方式插入最后的字段上使用(并建议使用)聚集索引,并保留顺序。

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

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

你不能试试这个,实验吗?我在这里有类似的情况,我有 40 亿行,不断地插入更多行(每秒最多 100 行),表没有主键也没有聚集索引,所以这个主题中的命题对我来说也很有趣。

于 2010-09-17T08:43:10.743 回答
1

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

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

于 2010-09-29T21:39:51.603 回答
1

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

绝不!想象一下,您需要在该表中放入另外一百万行并对其进行物理排序,从长远来看,这会造成巨大的性能损失。

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

绝对地。顺便说一句,聚集索引不是灵丹妙药,可能比普通索引慢。

于 2010-09-17T09:02:27.767 回答
0

i've been playing around with some etl stuff the last little bit. i went through jsut regularly inserting into the table, then removing and readding indexes before and after the insert, tried merge statements, then i finally tried ssis. I'm sold on ssis. Just yesterday i managed to cut an etl process (~24 million records, ~6gb) from ~1-1 1/2 hours per run to ~24 minutes, jsut by letting ssis handle the inserts.

i believe with advanced services you should be able to use ssis.

于 2010-09-17T15:33:25.167 回答
0

(鉴于您已经选择了答案并给了自己积分,这是作为免费服务提供的,是一种慈善行为!)

一点知识是一件危险的事情。有很多问题需要考虑;并且必须一起考虑。处理任何一个问题并孤立地检查它是管理数据库的一种非常分散的方式:您将永远发现一些新的事实并改变您以前的想法。在开始之前,请阅读此▶问题/答案◀了解上下文。

不要忘记,如今任何拥有键盘和调制解调器的人都可以发表他们的“论文”。他们中的一些人为 MS 工作,宣传最新的“增强”;其他人发布了他们从未使用过或仅使用过一次的功能的热情报告,在一种情况下,但他们发布说它在每种情况下都有效。(看看斯宾塞的回答:他很热情,“出卖”,但经过审查,这些说法是错误的;他不是一个坏人,只是典型的 MS 世界的群众,他们是如何运作的;他们是如何发布的。)

  • 注意:我使用术语 MicroSofties 来描述那些相信任何不合格的人都可以管理数据库的盖茨概念的人;那个MS会解决一切。这不是一种侮辱,而是一种爱,因为对魔法的信仰,以及对物理定律的悬置。

聚集指数

由真正的工程师(Sybase,在 MS 获得代码之前)为关系数据库设计,他们的大脑比所有 MS 的总和还要多。关系数据库有关系键,而不是Id物联网键。这些是多列键,可自动分配数据,因此插入负载,例如。一直插入各种公司的发票(尽管不在我们讨论的“块”的情况下)。

  • 如果您有良好的关系键,CI 提供范围查询(您的 (1) 和 (2) )以及其他 NCI 根本没有的优势。

  • 在对数据进行建模和规范化之前从Id列开始,严重阻碍了建模和规范化过程。

  • 如果您有Id物联网数据库,那么您将拥有更多的索引。许多 MS 数据库的内容不是“关系的”,它们通常只是非规范化的文件系统,具有比规范化数据库更多的索引。因此,有很大的推动力,很多 MS “增强” 试图给这些堕胎一点速度。修复症状,但不要靠近导致症状的问题。

  • 在 SQL 2005 和 2008 年,MS 再次使用 CI,结果是它们现在在某些方面更好,但在其他方面更糟;CI的普遍性已经丧失。

  • NCI 带有 CI 是不正确的(CI 是基本的单一存储结构;NCI 是辅助的,并且依赖于 CI;这就是为什么当您重新创建 CI 时,所有 NCI 都会自动重新创建)。NCI在叶级携带 CI密钥。

  • 微软有它的问题,随着主要版本的变化(但没有消除):

    • 而在 MS 中,这并没有有效地完成,因此 NCI 索引大小很大;在企业 DBMS 中,当这被有效地完成时,这不是一个考虑因素。

    • 因此,在 MS 世界中,CI 密钥应尽可能短的说法只对了一半。如果您了解考虑因素是 NCI 的大小,并且如果您愿意承担这笔费用,那么由于精心构建的 CI,它会返回一个非常快的表,那么这是最佳选择。

    • CI 应该是 iot 列的常见建议Id是完全错误的。CI 键的最差候选值是单调递增的值(IDENTITY、DATETIME 等)。为什么 ?因为您已经保证所有并发插入都将争夺当前插入位置,即索引上的最后一页。

    • 分区的真正目的(MS 比企业供应商晚了 10 年才提供)是为了分散这种负载。当然,他们必须提供一种分配分区的方法,猜猜看,不过是一个关系键;但首先,现在Idiot 密钥分布在 32 或 64 个分区上,提供更好的并发性。

  • CI 必须是唯一的。关系数据库需要唯一的键,所以这是显而易见的。

    • 但是对于那些将非关系内容倒入数据库的业余爱好者,如果他们不知道这个规则,但他们知道 CI 传播数据(有点知识是危险的事情),他们会将他们的Idiot 密钥保存在 NCI 中(好)但他们在一个几乎但不是很唯一的密钥上创建 CI。致命。CI 必须是唯一的,这是设计需求。重复(记住我们在这里讨论 CI 键)行在页面外,位于溢出页面和(然后)最后一页;并构成严重分裂页面链的方法。

    • 更新,因为这一点在其他地方受到质疑。 我已经说过 MS 不断改变方法而没有解决问题。

      • MS Online 手册,带有漂亮的图片(不是技术图表)告诉我们,在 2008 年,他们已经用可爱的“唯一性”替换(一个替换另一个)溢出页面。

      • 这完全满足了微软的要求。非唯一 CI 不是问题。它是由魔法处理的。结案。

      • 但是这些陈述没有逻辑或完整性,有资格的人会问明显的问题:这个“唯一性”在哪里?在每一行,或者只是需要“唯一化”的行。DBBC PAGE 显示它位于每一行。因此,MS 刚刚为每一行添加了一个 4 字节的秘密列(包括处理开销),而不是仅针对非唯一行添加几个溢出页面。这就是 MS 的工程理念。

      • 结束更新

    • 无论如何,要点仍然是,非唯一 CI 具有大量开销(现在比以前更多)并且应该避免。您最好自己添加一个 1 或 2 字节的列,以强制唯一性。.

  • 因此,从一开始(1984 年)就没有改变,CI 的最佳候选者是多列唯一的关系键(我不能肯定地说你的键是肯定的,但它肯定看起来像)。

  • 并将任何单调递增的键(IDENTITY、DATETIME)放入 NCI 中。

  • 还要记住 CI 是一个单一的存储结构,它消除了(否则)堆;CI B-Tree 与叶级别的行结婚;叶级条目行。这保证了每次访问都少读一次。

    • 因此,NCI+Heap 不可能比 CI 更快。MS 世界中违反物理定律的另一个常见神话:导航 B 树并写入您已经在的一个地方,必须比另外将行写入单独的存储结构更快。但是微软确实相信魔法,他们已经暂停了物理定律。
      .
  • 您还需要学习和使用许多其他功能,我至少会提到 FILLFACTOR 和 RESERVEPAGEGAP,以使这篇文章更加完整。在您了解这些功能之前,请勿使用它们。所有性能特性都有一个您需要理解和接受的成本。

  • CI 也可以在页面和范围级别进行自我修整,不会浪费空间。PageSplits 是需要监控的(仅随机插入),并且很容易被 FILLFACTOR 和 RESERVEPAGEGAP 调制。

  • 并阅读集群索引的 SO 网站,但请记住以上所有内容,尤其是。前两段。

您的具体案例

  • 无论如何,摆脱您的代理键(Idiot 列),并用真正的自然关系键替换它们。代理总是一个额外的键和索引;这是一个不应被遗忘或掉以轻心的代价。

  • CompanyIdentifier+DepartmentIdentifier+[uniquiefier] 正是我所说的。现在请注意,它们已经是 INT,而且速度非常快,因此添加NUMERIC(10,0) Idiot Key 非常愚蠢。使用 1 或 2 字节的列来强制唯一性。

  • 如果你做对了,你可能不需要分区许可证。

  • CompanyIdentifier+DepartmentIdentifier+[uniquifier] 在您定期执行批量删除/插入的上下文中,是 CI 的完美候选者(除了您发布的数据库之外,对您的数据库一无所知)。详述如上。

    • 与其他人所说的相反,这是一件好事,并且不会分散 CI。假设您有 20 家公司,您删除了 1 家,占数据的 5%。相当连续的整个 PageChain 现在被归入 FreePageChain,连续且完整。准确地说,你有一个单一的碎片点,但不是正常使用这个词的意义上的碎片。猜猜看,如果你转身执行批量插入,你认为数据会去哪里?这与已删除行的物理位置完全相同。FreePageChain 一次移动到 PageChain、extent 和 page。
      .
  • 但令人担忧的是,您不知道 CI 是唯一的需求。可悲的是,微软写了垃圾,但不是每个简单化规则的原因/内容;不是核心信息。非唯一 CI 的确切症状是,表在 DROP/CREATE CI 之后会立即非常快,然后随着时间的推移变慢。一个好的独特 CI 将保持其速度,并且需要一年的时间才能减速(在我的大型活跃银行数据库中需要 2 年)。

  • 4 小时对于 10 亿行来说是非常长的时间(我可以在企业平台上用 6 列键在 3 分钟内重新创建 160 亿行的 CI)。但无论如何,这意味着您必须将其安排为每周定期或按需维护。

  • 你为什么不使用 WITH SORTED_DATA 选项?你的数据不是在drop之前排序的吗?此选项重写 CI 非叶子页面,但不重写叶子页面(包含行)。只有当它确信数据已排序时,它才能做到这一点。不使用此选项会按物理顺序重写每一页。

现在,请善待。在你问我二十个问题之前,请先阅读并理解我在这里定义的所有问题。

于 2010-12-02T04:24:08.150 回答