分区策略

分区策略定义了是否应对特定表或具体化视图范围(数据分片)进行分区以及如何进行分区。

策略会触发一个额外的后台过程,该过程在创建盘区之后,在数据引入之后执行。 此过程包括从源盘区重新引入数据并生成同类盘区,其中指定为分区键的列的所有值都驻留在单个分区内

分区策略的主要目标是在支持的特定场景中增强查询性能。

注意

默认情况下,如果未定义数据分区策略(为 null),则盘区按创建(引入)时间进行分区。 在大多数情况下,无需设置数据分区策略。

支持的方案

下面是建议设置数据分区策略的唯一方案。 在所有其他情况下,不建议设置此策略。

  • 中等或高基数 stringguid 列的常用筛选器
    • 例如,多租户解决方案或指标表,其中的大多数查询或所有查询都会针对类型为 stringguid 的列(如 TenantIdMetricId)进行筛选。
    • 中等基数至少为 10,000 个非重复值。
    • 哈希分区键设置为 stringguid 列,并将 PartitionAssigmentMode 属性设置为 uniform
  • 在高基数 stringguid 列上频繁聚合或联接
    • 例如,来自许多不同传感器的 IoT 信息,或许多不同学生的学业记录。
    • 高基数是至少 1,000,000 个不同的值,其中,列中值的分布大致均匀。
    • 在这种情况下,请将哈希分区键设置为分组依据列或联接依据列,并将 PartitionAssigmentMode 属性设置为 ByPartition
  • 顺序外数据引入
    • 引入到表中的数据可能不会按照特定的 datetime 列(表示数据创建时间,通常用于筛选数据)排序并划分成区(分片)。 这可能是由于来自异类源文件的回填,这些文件包含时间跨度很大的日期/时间值。
    • 在这种情况下,请将统一范围日期/时间分区键设置为 datetime 列。
    • 如果需要让保留和缓存策略与列中的日期/时间值一致,而不是与引入时间一致,请将 OverrideCreationTime 属性设置为 true

注意

  • 对于定义了分区策略的表数量,没有设置硬编码限制。 但是,每个额外的表都会增加在群集节点上运行的后台数据分区过程的开销。 对更多表设置策略会导致使用更多群集资源,并且由于基础存储事务而导致更高的成本。 有关详细信息,请参阅容量
  • 如果每个分区的数据压缩大小预计小于 1GB,则建议不要设置分区策略。
  • 分区过程会导致分区过程中和合并过程中替换的所有盘区的存储工件残留。 大多数残留存储工件预计会在自动清理过程中被删除。 增加 MaxPartitionCount 属性的值会增加残留存储工件的数量,并会降低清理性能。
  • 在对具体化视图应用分区策略之前,请查看有关具体化视图分区策略的建议。

分区键

支持以下类型的分区键。

种类 列类型 分区属性 分区值
哈希 stringguid FunctionMaxPartitionCountSeedPartitionAssignmentMode Function (ColumnNameMaxPartitionCountSeed)
统一范围 datetime RangeSizeReferenceOverrideCreationTime bin_at(ColumnName, RangeSize, Reference)

哈希分区键

如果策略包括“哈希分区键”,属于同一分区的所有同类盘区将被分配到群集中的同一数据节点。

注意

数据分区操作增加了大量处理负荷。 建议仅在以下条件下对表应用哈希分区键:

  • 大多数查询都使用相等筛选器 (==, in())。
  • 大多数查询在类型为 stringguid 的特定列上进行聚合/联接,该列是大维度(10M 或更高的基数)的,例如 device_IDuser_ID
  • 分区表的使用模式为高并发查询负载,例如,在监视或仪表板应用程序中就是如此。
  • 哈希取模函数用于对数据进行分区。
  • 同类(已分区)盘区中的数据按哈希分区键排序。
    • 如果表上定义了哈希分区键,则不需要在行顺序策略中包含哈希分区键。
  • 如果查询使用无序策略,并且按照此策略,joinsummarizemake-series 中使用的 shuffle key 是表的哈希分区键,那么查询的性能将会更好,因为需要跨群集节点移动的数据量减少。

分区属性

properties 说明 支持的值 建议的值
Function 要使用的哈希取模函数的名称。 XxHash64
MaxPartitionCount 每个时间段要创建的最大分区数(哈希取模函数的取模参数)。 (1,2048] 范围内。 值越大,群集节点上数据分区过程的开销就越大,每个时间段的区数量也就越大。 建议值为 128。 较高的值将显著增加引入后数据分区的开销以及元数据的大小 - 因此不建议使用。
Seed 用于将哈希值随机化。 正整数。 1,这也是默认值。
PartitionAssignmentMode 用于将分区分配给群集中节点的模式。 ByPartition:属于同一分区的所有同类(已分区)盘区都分配给同一个节点。
Uniform:将忽略区的分区值。 区将统一分配给群集的节点。
如果查询不根据哈希分区键联接或聚合,请使用 Uniform。 否则使用 ByPartition

哈希分区键示例

名为 tenant_idstring 类型列的哈希分区键。 它使用 XxHash64 哈希函数,并将 MaxPartitionCount 设置为建议的值 128,将默认值 Seed 设置为 1

{
  "ColumnName": "tenant_id",
  "Kind": "Hash",
  "Properties": {
    "Function": "XxHash64",
    "MaxPartitionCount": 128,
    "Seed": 1,
    "PartitionAssignmentMode": "Uniform"
  }
}

统一范围日期/时间分区键

注意

只有当引入到表中的数据不太可能根据此列排序时,才对表中的 datetime 类型的列应用统一范围的日期/时间分区键。

在这些情况下,你可以在区之间重新组织数据,以便每个区都包括有限时间范围的记录。 此过程会使 datetime 列上的筛选器在查询时更有效。

使用的分区函数是 bin_at(),该函数不可自定义。

分区属性

properties 说明 建议的值
RangeSize 一个 timespan 标量常量,指示每个日期/时间分区的大小。 从值 1.00:00:00(一天)开始。 不要设置更短的值,因为这可能会导致表中有大量无法合并的小区。
Reference 一个 datetime 标量常量,指示一个固定的时间点,根据该时间点调整日期/时间分区。 1970-01-01 00:00:00 开始。 如果存在日期/时间分区键具有 null 值的记录,则将其分区值设置为 Reference
OverrideCreationTime 一个 bool,表示是否应使用分区键中值的范围替代结果区的最小和最大创建时间。 默认为 false。 如果未按到达时间顺序引入数据,则此项设置为 true。 例如,单个源文件可能包含较远的日期/时间值,并且/或者你可能希望根据日期/时间值而不是引入时间强制实施保留或缓存。

OverrideCreationTime 设置为 true 时,合并过程中可能会丢失区。 如果区创建时间早于表的区合并策略Lookback 时间段,则会丢失区。 若要确保区可发现,请将 Lookback 属性设置为 HotCache

统一范围日期/时间分区示例

以下代码片段显示了针对名为 timestampdatetime 类型列的统一日期/时间范围分区键。 它使用 datetime(2021-01-01) 作为其参考点,每个分区的大小为 7d,并且它不会替代区的创建时间。

{
  "ColumnName": "timestamp",
  "Kind": "UniformRange",
  "Properties": {
    "Reference": "2021-01-01T00:00:00",
    "RangeSize": "7.00:00:00",
    "OverrideCreationTime": false
  }
}

策略对象

表的数据分区策略默认为 null,在这种情况下,将不会在引入数据后对表中的数据进行分区。

数据分区策略具有以下主要属性:

  • PartitionKeys

    • 分区键的集合,用于定义如何对表中的数据进行分区。
    • 一个表最多可以有 2 个分区键,并有下列选项之一:
    • 每个分区键都具有以下属性:
      • ColumnNamestring - 将根据其对数据进行分区的列的名称。
      • Kindstring - 要应用的数据分区类型(HashUniformRange)。
      • Propertiesproperty bag -根据完成的分区定义参数。
  • EffectiveDateTime

    • 策略生效的 UTC 日期/时间。
    • 此属性是可选的。 如果未指定它,则策略将对应用了策略后引入的数据生效。

注意

  • 你可以设置过去的一个日期/时间值,并对已引入的数据分区。 但是,这种做法可能会显著增加分区过程中使用的资源。
  • 在大多数情况下,建议仅将新引入的数据分区,并避免对大量历史数据进行分区。
  • 如果选择对历史数据进行分区,请考虑逐步执行此操作,方法是:每次更改策略时,将 EffectiveDateTime 设置为之前几天的 datetime

数据分区示例

具有两个分区键的数据分区策略对象。

  1. 名为 tenant_idstring 类型列的哈希分区键。
    • 它使用 XxHash64 哈希函数,并将 MaxPartitionCount 设置为建议的值 128,将默认值 Seed 设置为 1
  2. 名为 timestampdatetime 类型列的统一日期/时间范围分区键。
    • 它使用 datetime(2021-01-01) 作为参考点,每个分区的大小为 7d
{
  "PartitionKeys": [
    {
      "ColumnName": "tenant_id",
      "Kind": "Hash",
      "Properties": {
        "Function": "XxHash64",
        "MaxPartitionCount": 128,
        "Seed": 1,
        "PartitionAssignmentMode": "Uniform"
      }
    },
    {
      "ColumnName": "timestamp",
      "Kind": "UniformRange",
      "Properties": {
        "Reference": "2021-01-01T00:00:00",
        "RangeSize": "7.00:00:00",
        "OverrideCreationTime": false
      }
    }
  ]
}

其他属性

可以将以下属性定义为策略的一部分。 这些属性是可选的,建议不要更改它们。

properties 说明 建议的值 默认值
MinRowCountPerOperation 单个数据分区操作的源盘区行数总和的最小目标值。 0
MaxRowCountPerOperation 单个数据分区操作的源盘区行数总和的最大目标值。 如果看到单个分区操作消耗了大量的内存或 CPU,请设置一个小于 5M 的值。 0,默认目标是 5,000,000 条记录。
MaxOriginalSizePerOperation 单个数据分区操作的源盘区的原始大小之和(以字节为单位)的最大目标。 如果分区操作每次操作消耗大量内存或 CPU,请设置小于 5 GB 的值。 0,默认目标是 5,368,709,120 字节 (5 GB)。

数据分区过程

  • 数据分区在群集中作为引入后的后台进程运行。
    • 持续引入到的表应始终具有尚未分区的数据的“尾部”(非同类区)。
  • 无论策略中 EffectiveDateTime 属性的值如何,数据分区只在热盘区上运行。
    • 如果需要对冷区进行分区,则需要临时调整缓存策略

可以使用 .show database extents partitioning statistics 命令监视数据库中具有已定义的策略的表的分区状态。

分区容量

  • 数据分区过程会导致创建更多的盘区。 群集可以逐渐增加其区合并容量,以便合并区的过程可以赶上进度。
  • 如果有较高的引入吞吐量,或者有足够多的表定义了分区策略,则群集可能会逐渐增加其盘区分区容量,以便分区盘区的过程可以保持。
  • 为了避免消耗过多资源,对这些动态增加进行了限制。 如果它们全部耗尽,则可能需要逐渐线性地增加,以超过上限。
    • 如果增加容量会显著增加群集资源的使用,则可以手动或通过启用自动缩放来横向/纵向扩展群集

限制

  • 在已具有 5,000,000 个以上区的数据库中对数据进行分区的尝试会受到限制。
    • 在这种情况下,数据库中表的分区策略的 EffectiveDateTime 属性将自动延迟几个小时,以便你可以重新评估配置和策略。

已分区列中的离群值

  • 以下情况可能会导致群集节点上的数据分布不均衡,并降低查询性能:
    • 如果某个哈希分区键包含比其他值要普遍得多的值,例如,空字符串或泛型值(例如 nullN/A)。
    • 这些值表示在数据集中更为普遍的实体(例如 tenant_id)。
  • 如果统一范围日期/时间分区键包含的大部分值与列中的大多数值“相差甚远”,则会增加数据分区过程的开销,并可能会导致群集需要跟踪多个小区。 这种情况的一个示例是来自遥远的过去或未来的日期/时间值。

在这两种情况下,要么“修复”数据,要么在数据引入之前或引入时筛选掉数据中不相关的记录,以减少群集上数据分区的开销。 例如,使用更新策略