10

我面临以下问题。我有一张非常大的桌子。这张桌子是以前参与该项目的人的遗产。该表位于 MS SQL Server 中。

该表具有以下属性:

  1. 它有大约 300 列。它们都有“文本”类型,但其中一些最终应该代表其他类型(例如,整数或日期时间)。因此,在使用之前必须将这些文本值转换为适当的类型
  2. 该表有超过 100 百万行。表的空间很快就会达到 1 TB
  3. 该表没有任何索引
  4. 该表没有任何已实现的分区机制。

正如您可能猜到的那样,不可能对该表运行任何合理的查询。现在人们只在表中插入新记录,但没有人使用它。所以我需要重组它。我计划创建一个新结构并用旧表中的数据重新填充新结构。显然,我将实现分区,但这不是唯一要做的事情。

该表最重要的特性之一是那些纯文本字段(即它们不必转换为另一种类型)通常具有频繁重复的值。因此,给定列中值的实际变化范围是 5-30 个不同的值。这引发了进行规范化的想法:对于每个这样的文本列,我将创建一个附加表,其中包含可能出现在该列中的所有不同值的列表,然后我将在这个附加表中创建一个(tinyint)主键和然后将在原始表中使用适当的外键,而不是将这些文本值保留在原始表中。然后我会在这个外键列上放一个索引。以这种方式处理的列数约为 100。

它提出了以下问题:

  1. 这种规范化真的会提高对这 100 个领域中的一些领域施加条件的速度吗?如果我们忘记保留这些列所需的大小,是否会由于使用 tinyint-columns 替换初始文本列而提高性能?如果我不进行任何规范化并简单地在这些初始文本列上放置一个索引,那么性能是否与计划的 tinyint-column 上的索引相同?
  2. 如果我进行所描述的规范化,那么构建一个显示文本值的视图将需要将我的主表与大约 100 个附加表连接起来。一个积极的时刻是我将为“主键”=“外键”对进行这些连接。但是仍然应该加入相当多的表。这里有一个问题:对这个视图进行的查询的性能与对初始非规范化表的查询的性能相比是否会更差?SQL Server 优化器是否真的能够以允许利用规范化优势的方式优化查询?

抱歉这么长的文字。

感谢您的每一条评论!

PS 我创建了一个关于加入 100 个表的相关问题; 加入 100 个表

4

4 回答 4

7

除了针对数据运行的查询速度之外,您还会发现规范化数据的其他好处......例如大小和可维护性,仅此一项就应该证明规范化它是合理的......

但是,它也可能会提高查询速度;目前单行包含 300 个文本列是巨大的,并且几乎可以肯定超过了存储行数据页的 8,060 字节限制......而是存储在ROW_OVERFLOW_DATALOB_DATA分配单元中。

通过规范化减少每一行的大小,例如用TINYINT外键替换冗余文本数据,以及将不依赖于这个大表主键的列删除到另一个表中,数据应该不再溢出,并且您' 还可以在每页存储更多行。

至于通过执行JOIN获取规范化数据而增加的开销......如果您正确索引表,这不应该增加大量开销。但是,如果它确实增加了不可接受的开销,那么您可以根据需要选择性地对数据进行反规范化。

于 2013-02-07T19:21:11.713 回答
5

这是否值得努力取决于价值观的持续时间。如果值是州缩写(2 个字符)或国家代码(3 个字符),则生成的表将比现有表更大。请记住,您需要包含引用表的主键。这通常是一个整数并占用四个字节。

这样做还有其他充分的理由。拥有具有有效值列表的引用表可以保持数据库的一致性。参考表既可用于验证输入,也可用于报告目的。可以包括附加信息,例如“长名称”或类似的东西。

此外,SQL Server 会将 varchar 列溢出到其他页面上。它不会溢出其他类型。您只有 300 列,但最终您的记录数据可能会接近单页数据的 8k 限制。

而且,如果您决定继续,我建议您在列中查找“主题”。可能存在可以组合在一起的多组列。. . 详细的停止代码和停止类别、简短的企业名称和完整的企业名称。您正在走上对数据建模的道路(一件好事)。但是要谨慎对待在非常低的级别(管理 100 个参考表)而不是识别一组合理的实体和关系。

于 2013-02-07T19:18:09.477 回答
2

1) 系统当前必须对非常大量的数据进行全表扫描,从而导致性能问题。优化的许多方面可以提高这种性能。将列转换为正确的数据类型不仅可以通过减小每条记录的大小来显着提高性能,而且可以使数据正确。如果查询列,您当前正在查看与字段中的文本进行比较的文本。仅使用索引可以改善这一点,但更改为查找将允许从足够小的表中查找 ID 值以保存在内存中,然后使用它来仅扫描整数值,这是一个更快的过程。2)如果数据被规范化为第三范式等,然后您可以看到以数据完整性为名的性能受到影响的实例。如果引擎在不首先投影数据的情况下无法计算出如何限制行,这将是一个最大的问题。但是,如果确实发生了这种情况,则执行计划可以识别出这种情况,并且可以修改查询以降低发生这种情况的可能性。

还有一点需要注意的是,听起来如果数据库结构合理,它可能能够缓存在内存中,因为数据量会大大减少。如果是这样,那么性能将大大提高。

提高性能的快速方法可能是添加索引。但是,这将进一步增加整体数据库大小,并且不能解决存储重复数据的问题和可能的数据完整性问题。

还可以进行一些其他更改 - 如果并非总是需要大量数据,则可以将其分离到相关表中,并仅根据需要进行查找。不用于查找其他表的字段特别适用于此,因为连接可以在一个小得多的表上,同时保留一个相当简单的结构,当您确定您实际的数据时只查找附加数据需要。这显然不是一个正确规范化的结构,但可能是提高性能的一种快速而肮脏的方式(在添加索引之后)。

于 2013-02-07T19:16:39.757 回答
1
  1. 在您的头脑中和纸上构建一个规范化的数据库结构
  2. 构建数据库(带索引)
  3. 解构那个巨石。事情看起来不会那么糟糕。我猜会重复很多(我的意思是很多)数据
  4. 创建 SQL 插入语句以将数据插入数据库
  5. 首先用猎枪去找那些制造那个噩梦的人。玩得开心。
于 2013-02-07T19:29:46.257 回答