代码之家  ›  专栏  ›  技术社区  ›  rusty

基于模函数的SQL Server表分区?

  •  5
  • rusty  · 技术社区  · 16 年前

    我有一个非常大的表(1000多万行),它开始显示查询性能下降的迹象。由于这个表的大小很快可能会增加一倍或三倍,所以我正在考虑对表进行分区以挤出一些查询性能。

    桌子看起来像这样:

    CREATE TABLE [my_data] (
        [id] [int] IDENTITY(1,1) NOT NULL,
        [topic_id] [int] NULL,
        [data_value] [decimal](19, 5) NULL
    )
    

    所以,任何给定主题的一系列值。此表上的查询将始终按主题ID进行,因此(ID,主题ID)上有一个聚集索引。

    无论如何,由于主题ID没有边界(可以添加任意数量的主题),我想尝试在主题ID的模函数上对这个表进行分区。比如:

    topic_id % 4 == 0 => partition 0
    topic_id % 4 == 1 => partition 1
    topic_id % 4 == 2 => partition 2
    topic_id % 4 == 3 => partition 3
    

    但是,在决定分区时,我没有看到任何方法可以告诉“创建分区函数”或“创建分区方案”来执行此操作。

    这是可能的吗?如何根据对输入值执行的操作生成分区函数?

    4 回复  |  直到 15 年前
        1
  •  5
  •   Matt Whitfield    16 年前

    您只需要将模数列创建为持久化计算列。

    Blue Peter Style,这是我之前做的(尽管我不能100%确定分区值子句是否正确):

    CREATE PARTITION FUNCTION [PF_PartitonFour] (int)
    AS RANGE RIGHT
    FOR VALUES (
      0,
      1,
      2)
    GO
    
    CREATE PARTITION SCHEME [PS_PartitionFourScheme]
    AS PARTITION [PF_PartitonFour]
    TO ([TestPartitionGroup1],
        [TestPartitionGroup2],
        [TestPartitionGroup3],
        [TestPartitionGroup4])
    GO
    
    CREATE TABLE [my_data] (
      [id] [int] IDENTITY(1,1) NOT NULL,
      [topic_id] [int] NULL,
      [data_value] [decimal](19, 5) NULL
      [PartitionElement] AS [topic_id] % 4 PERSISTED,
    ) ON [PS_PartitionFourScheme] (PartitionElement);
    GO
    
        2
  •  3
  •   Remus Rusanu    16 年前

    哈希分区在SQL Server 2005/2008中不可用。必须使用范围分区。

    也就是说,您应该知道分区主要是一个存储选项,请参见 Partitioned Table and Index Concepts 以下内容:

    分区生成大表或 索引更多 可管理的 ,因为 分区使您能够 管理 和 快速访问数据子集 高效,同时保持 数据收集的完整性。通过 使用分区,这样的操作 作为 加载数据 从OLTP到AN OLAP系统只需几秒钟, 而不是分钟和小时 操作采用的早期版本 SQLServer。 维护 操作 在数据子集上执行的 更有效地执行 因为这些行动只针对 所需的数据,而不是 整张桌子。

    如您所见,在msdn中引入分区的重点是维护、可管理性和数据加载。根据我的经验,分区最多可以获得0个性能增益。尤其是在SQL 2005中。通常会导致性能下降。为了提高性能,应该使用正确的聚集索引和正确设计的非聚集索引。

    在SQL 2008中,如果从IO的角度正确地分布了并行操作符,那么它们在分区方面有了改进,请参见 Designing Partitions to Improve Query Performance . 但是,它们的好处是微乎其微的,并且被一组适当设计的聚集索引和非聚集索引的好处所掩盖。举例来说,(id,topic_id)中的聚集索引,其中id是一个标识,仅用于按id查找单个项目。另一方面,(topic_id,id)的聚集索引将有益于查找特定主题的任何查询。我不知道您的系统需求和您运行的查询,但是在这么窄的表上有1000万行的性能问题,有点像索引和查询问题,没有分区问题。

        3
  •  0
  •   Sam    16 年前

    从文档中,您似乎必须为函数赋予值:

    要创建4个分区…

    CREATE PARTITION FUNCTION myRangePF1 (int)
    AS RANGE LEFT FOR VALUES (1, 100, 1000);
    

    难道你就不能在这个调用上进行计算,找到合适的值来进行拆分吗?是否将值替换为调用?或者我不明白你为什么要用模量?根据您的ID可能有缺口,您可能需要使用一些统计数学来找出分区的位置。

    CREATE PARTITION FUNCTION myRangePF1 (int)
    AS RANGE LEFT FOR VALUES (@low, @Med, @High);
    
        4
  •  0
  •   onupdatecascade    16 年前

    对于SQL Server来说,1000万行并不是那么多;常规的索引设计可能可以解决这个问题,而不需要分区。如前所述,尝试在不同的列集合上进行集群;在topicid上进行集群,id看起来像是要测试的东西,特别是在大多数查询都以topicid为标准的情况下。类似这样的聚集索引与分区的效果大致相同,至少它将磁盘上的相关数据行分组在一起,并允许范围扫描快速获取它们。

    如果该设计有效,那么您只需要担心插入的碎片,但这是可以管理的。正确建立索引之后,确保有足够的RAM,并且没有磁盘瓶颈。

    推荐文章