在 SQL Server 中对大型表进行分区的最佳方法是啥?

Posted

技术标签:

【中文标题】在 SQL Server 中对大型表进行分区的最佳方法是啥?【英文标题】:What is the best way to partition large tables in SQL Server?在 SQL Server 中对大型表进行分区的最佳方法是什么? 【发布时间】:2008-10-03 19:00:41 【问题描述】:

在最近的一个项目中,“首席”开发人员设计了一个数据库模式,其中“较大”的表将被拆分到两个独立的数据库中,主数据库的视图将两个独立的数据库表联合在一起。主数据库是应用程序的驱动程序,因此这些表看起来和感觉就像普通表(除了一些关于更新的古怪事情)。这似乎是一个巨大的性能问题。我们确实看到了这些桌子周围的性能问题,但没有什么能让他改变对他的设计的看法。只是想知道最好的方法是什么,或者是否值得这样做?

【问题讨论】:

【参考方案1】:

我认为通过在单个服务器中跨多个数据库对表进行分区,您不会真正获得任何收益。基本上你所做的一切首先通过在单个 SQL Server 实例下拥有多个实例(即在两个不同的数据库中打开)增加了使用“表”的开销。

您有多大的数据集?我有一个客户端,在 SQL Server 中有一个 600 万行的表,其中包含 2 年的销售数据。他们将其用于交易和报告,没有任何明显的速度问题。

调整索引和选择正确的聚集索引当然对性能至关重要。

如果您的数据集非常大并且您正在寻找分区,那么您将获得更多的收益,因为您可以在物理服务器上对表进行分区。

【讨论】:

【参考方案2】:

分区不是一件轻而易举的事情,因为它可能会对性能产生许多微妙的影响。

我的第一个问题是,您是指将较大的表对象放在单独的文件组中(在单独的主轴上)还是指在表对象内部进行数据分区?

我怀疑所描述的情况是试图将某些大型表的物理存储放在与其余表不同的轴上。在这种情况下,增加单独数据库的额外开销、失去跨数据库强制执行参照完整性的任何能力以及启用跨数据库所有权链接的安全隐患与在单个数据库中使用多个文件组相比没有任何好处。如果很可能,您在问题中引用的单独数据库甚至没有存储在单独的主轴上,而是全部存储在同一个主轴上,那么您甚至可以否定通过物理分离磁盘活动可以获得的轻微性能优势和完全没有得到任何好处。

我建议不要使用其他数据库来保存大型表,而是查看 SQL Server 联机丛书中的文件组主题或快速查看article:

如果您对数据分区(包括分区到多个文件组)感兴趣,那么我建议您阅读 Kimberly Tripp 的文章,他在 SQL Server 2005 发布时就该处可用的改进进行了出色的演示。一个好的起点是whitepaper

【讨论】:

SQLTeam.com 最近也有关于分区和自动化维护的帖子:weblogs.sqlteam.com。【参考方案3】:

您使用的是哪个版本的 SQL Server? SQL Server 2005 有分区表,但在 2000(或 7.0)中,您需要使用分区视图。

另外,将表分区放在单独的数据库中的原因是什么?

过去(2005 年之前)我不得不对表进行分区时,通常是按日期列或类似的东西,以查看各个分区。 Books Online 有一个部分讨论如何执行此操作以及围绕它的所有规则。您需要遵守规则才能使其按应有的方式工作。

要记住的关键是您的分区列必须是主键的一部分,并且您希望在对表的任何访问中始终使用该列,以便优化器可以忽略不应该受到影响的分区查询。

在 MSDN 中查找“分区表”,您应该能够找到更完整的 SQL Server 2005 分区表教程以及如何设置它们以获得最佳性能的建议。

【讨论】:

【参考方案4】:

您是在询问数据库设计方面的最佳实践,还是在说服您的领导改变主意? :)

在设计方面...回到过去,有时需要垂直分区来解决数据库引擎的限制,其中表中的列数是硬性限制,例如 255 列。如今,主要好处纯粹是为了提高性能:将很少使用的列或 blob 放在单独的磁盘阵列上。但是,如果您经常从两张桌子上取东西,那可能会是一种损失。听起来您的潜在客户正遭受过早优化的困扰。

就告诉你的领导是错误的而言......这需要外交。如果他意识到在表现方面的不满,那么基准可能是显示差异的最佳方式。

使用“create table t1 as select * from view1”在某处创建一个新的物理表,然后使用垂直分区表和新表运行一些冗长的批处理。如果真像你说的那么差,那区别应该很明显了。

但这也可能是过早的优化。了解最终用户对性能的看法。如果性能足够好,对于某些好的定义,那么不要修复没有破坏的东西。

【讨论】:

【参考方案5】:

表分区有一个明确的好处(无论它是在相同还是不同的文件组/磁盘上)。如果正确选择了分区列,您将意识到您的查询将只命中所需的分区。所以想象一下,如果你有 1 亿条记录(我的分区表比这大得多 - 大约 20+ 十亿行),如果在大多数情况下,超过 70% 的数据访问只是某个类别或时间线或类型数据,那么它有助于将访问最多的数据保存在单独的分区中。此外,您可以将分区与具有各种类型磁盘(SATA、光纤通道、SSD)的单独文件组对齐,以便访问最多/繁忙的数据位于最快的存储上,而访问最少/很少访问的数据实际上位于较慢的磁盘上。

虽然,与 Oracle 不同,SQL Server 的分区能力有限。您只能选择一列进行分区(即使在 SQL 2008 中)。因此,您必须明智地选择一个列,该列也是您大多数频繁查询的一部分。在大多数情况下,人们发现选择按日期列进行分区很容易。但是,尽管以这种方式分区似乎是合乎逻辑的,但如果您的查询没有将该列作为条件的一部分,那么您将不会从分区中获得足够的好处(换句话说,您的查询无论如何都会命中所有分区)。

数据仓库/数据挖掘类型数据库的分区比 OLTP 容易得多,因为大多数 DW 数据库查询都受到时间段的限制。

这就是为什么现在由于数据库处理的数据量很大,明智的做法是设计应用程序,使查询受到时间、地理位置等更广泛的组的限制,这样当这些列选择进行分区,您将获得最大的收益。

【讨论】:

【参考方案6】:

我不同意分区不能获得任何好处的假设。

如果分区数据在物理和逻辑上是对齐的,那么查询的潜在 IO 应该会大大减少。

例如,我们有一个表,其中批处理字段为 INT,表示一个 INT。

如果我们按此字段对数据进行分区,然后针对特定批次重新运行查询,我们应该能够在分区前后运行 set statistics io ON 并看到 IO 减少,

如果我们每个分区有一百万行,并且每个分区都写入一个单独的设备。查询应该能够消除不必要的分区。

我没有在 SQL Server 上做过很多分区,但我确实有在 Sybase ASE 上进行分区的经验,这就是所谓的分区消除。当我有时间时,我将在 SQL Server 2005 机器上测试该场景。

【讨论】:

我看不到按批处理字段对表进行分区会导致更少的 IO。如果批处理是正确索引的一部分,它将减少需要读取的行数,而不管分区如何。现在 IO 是需要读取的数据行的函数。分区如何改进? 几个物理设备之间的分区表如何比配置跨越这些设备的文件组更好,正如 Joe Kuemerle 所建议的那样?我知道在某些非常特殊的情况下,手动设置会更有效。但这不是一个非常特殊的情况吗?我想通常购买更大的 RAID 比让您的开发人员和 DBA 花费大量时间移动表更便宜。

以上是关于在 SQL Server 中对大型表进行分区的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

sql server 分区(上)

sql 在Postgres中对表进行分区

SQL Server 中对大型数据集的慢速不同查询

sqlserver中分表和分库有啥区别

在 Hive 中对表进行分区和分桶有啥区别?

如何在 SQL Redshift 中对表进行分区后比较两列的值