跳到主要内容
版本: 最新版本-3.5

数据分布

在创建表时配置适当的分区和分桶可以帮助实现均匀的数据分布。均匀的数据分布是指按照一定的规则将数据划分为子集,并将其均匀分布在不同的节点上。它还可以减少扫描的数据量,充分利用集群的并行处理能力,从而提高查询性能。

注意

  • 如果在创建表时指定了数据分布,并且业务场景中的查询模式或数据特征发生了变化,那么自 v3.2 起,StarRocks 支持在创建表后修改某些与数据分布相关的属性,以满足最新业务场景的查询性能需求。
  • 自 v3.1 起,在创建表或添加分区时,您无需在 DISTRIBUTED BY 子句中指定分桶键。StarRocks 支持随机分桶,它会将数据随机分布到所有桶中。有关更多信息,请参阅随机分桶
  • 自 v2.5.7 起,您可以选择在创建表或添加分区时不手动设置桶数。StarRocks 可以自动设置桶数 (BUCKETS)。但是,如果在 StarRocks 自动设置桶数后,性能未达到您的预期,并且您熟悉分桶机制,您仍然可以手动设置桶数

简介

通用分布方法

现代分布式数据库系统通常使用以下基本分布方法:循环、范围、列表和哈希。

Data distribution method

  • 循环:将数据循环地分布到不同的节点上。
  • 范围:根据分区列值的范围将数据分布到不同的节点上。如图所示,范围 [1-3] 和 [4-6] 对应于不同的节点。
  • 列表:根据分区列的离散值将数据分布到不同的节点上,例如性别和省份。每个离散值都映射到一个节点,多个不同的值可能会映射到同一个节点。
  • 哈希:根据哈希函数将数据分布到不同的节点上。

为了实现更灵活的数据分区,除了使用上述数据分布方法之一外,您还可以根据具体的业务需求组合这些方法。常见的组合包括哈希 + 哈希、范围 + 哈希和哈希 + 列表。

StarRocks 中的分布方法

StarRocks 支持单独和组合使用数据分布方法。

注意

除了通用的分布方法外,StarRocks 还支持随机分布以简化分桶配置。

此外,StarRocks 通过实现两级分区 + 分桶方法来分布数据。

  • 第一级是分区:可以对表中的数据进行分区。支持的分区方法包括表达式分区、范围分区和列表分区。或者您可以选择不使用分区(整个表被视为一个分区)。
  • 第二级是分桶:分区中的数据需要进一步分布到更小的桶中。支持的分桶方法包括哈希分桶和随机分桶。
分布方法分区和分桶方法描述
随机分布随机分桶整个表被视为一个分区。表中的数据随机分布到不同的桶中。这是默认的数据分布方法。
哈希分布哈希分桶整个表被视为一个分区。表中的数据根据数据分桶键的哈希值,通过哈希函数分布到相应的桶中。
范围 + 随机分布
  1. 表达式分区或范围分区
  2. 随机分桶
  1. 表中的数据根据分区列值所在的范围分布到相应的分区中。
  2. 分区中的数据随机分布到不同的桶中。
范围 + 哈希分布
  1. 表达式分区或范围分区
  2. 哈希分桶
  1. 表中的数据根据分区列值所在的范围分布到相应的分区中。
  2. 分区中的数据根据数据分桶键的哈希值,通过哈希函数分布到相应的桶中。
列表 + 随机分布
  1. 表达式分区或列表分区
  2. 随机分桶
  1. 表中的数据根据分区列值所在的范围分布到相应的分区中。
  2. 分区中的数据随机分布到不同的桶中。
列表 + 哈希分布
  1. 表达式分区或列表分区
  2. 哈希分桶
  1. 表中的数据根据分区列值所属的值列表进行分区。
  2. 分区中的数据根据数据分桶键的哈希值,通过哈希函数分布到相应的桶中。
  • 随机分布

    如果在创建表时不配置分区和分桶方法,则默认使用随机分布。此分布方法目前只能用于创建 Duplicate Key 表。

    CREATE TABLE site_access1 (
    event_day DATE,
    site_id INT DEFAULT '10',
    pv BIGINT DEFAULT '0' ,
    city_code VARCHAR(100),
    user_name VARCHAR(32) DEFAULT ''
    )
    DUPLICATE KEY (event_day,site_id,pv);
    -- Because the partitioning and bucketing methods are not configured, random distribution is used by default.
  • 哈希分布

    CREATE TABLE site_access2 (
    event_day DATE,
    site_id INT DEFAULT '10',
    city_code SMALLINT,
    user_name VARCHAR(32) DEFAULT '',
    pv BIGINT SUM DEFAULT '0'
    )
    AGGREGATE KEY (event_day, site_id, city_code, user_name)
    -- Use hash bucketing as the bucketing method and must specify the bucketing key.
    DISTRIBUTED BY HASH(event_day,site_id);
  • 范围 + 随机分布(此分布方法目前只能用于创建 Duplicate Key 表。)

    CREATE TABLE site_access3 (
    event_day DATE,
    site_id INT DEFAULT '10',
    pv BIGINT DEFAULT '0' ,
    city_code VARCHAR(100),
    user_name VARCHAR(32) DEFAULT ''
    )
    DUPLICATE KEY(event_day,site_id,pv)
    -- Use expression partitioning as the partitioning method and configure a time function expression.
    -- You can also use range partitioning.
    PARTITION BY date_trunc('day', event_day);
    -- Because the bucketing method is not configured, random bucketing is used by default.
  • 范围 + 哈希分布

    CREATE TABLE site_access4 (
    event_day DATE,
    site_id INT DEFAULT '10',
    city_code VARCHAR(100),
    user_name VARCHAR(32) DEFAULT '',
    pv BIGINT SUM DEFAULT '0'
    )
    AGGREGATE KEY(event_day, site_id, city_code, user_name)
    -- Use expression partitioning as the partitioning method and configure a time function expression.
    -- You can also use range partitioning.
    PARTITION BY date_trunc('day', event_day)
    -- Use hash bucketing as the bucketing method and must specify the bucketing key.
    DISTRIBUTED BY HASH(event_day, site_id);
  • 列表 + 随机分布(此分布方法目前只能用于创建 Duplicate Key 表。)

    CREATE TABLE t_recharge_detail1 (
    id bigint,
    user_id bigint,
    recharge_money decimal(32,2),
    city varchar(20) not null,
    dt date not null
    )
    DUPLICATE KEY(id)
    -- Use expression partitioning as the partitioning method and specify the partitioning column.
    -- You can also use list partitioning.
    PARTITION BY (city);
    -- Because the bucketing method is not configured, random bucketing is used by default.
  • 列表 + 哈希分布

    CREATE TABLE t_recharge_detail2 (
    id bigint,
    user_id bigint,
    recharge_money decimal(32,2),
    city varchar(20) not null,
    dt date not null
    )
    DUPLICATE KEY(id)
    -- Use expression partitioning as the partitioning method and specify the partitioning column.
    -- You can also use list partitionifng.
    PARTITION BY (city)
    -- Use hash bucketing as the bucketing method and must specify the bucketing key.
    DISTRIBUTED BY HASH(city,id);

分区

分区方法将表划分为多个分区。分区主要用于基于分区键将表拆分为不同的管理单元(分区)。您可以为每个分区设置存储策略,包括桶数、热冷数据存储策略、存储介质类型以及副本数。StarRocks 允许您在集群中使用不同类型的存储介质。例如,您可以将最新数据存储在固态硬盘 (SSD) 上以提高查询性能,并将历史数据存储在 SATA 硬盘上以降低存储成本。

分区方法使用场景创建分区的方法
表达式分区(推荐)以前称为自动分区。这种分区方法更灵活且易于使用。它适用于大多数场景,包括基于连续日期范围或枚举值查询和管理数据。在数据加载期间自动创建
范围分区(旧版)典型的使用场景是存储简单、有序的数据,这些数据通常基于连续的日期/数值范围进行查询和管理。例如,在某些特殊情况下,历史数据需要按月分区,而最近的数据需要按天分区。手动、动态或批量创建
列表分区(旧版)典型的使用场景是基于枚举值查询和管理数据,并且一个分区需要包含每个分区列的不同值的数据。例如,如果您经常基于国家和城市查询和管理数据,则可以使用此方法并选择 city 作为分区列。因此,一个分区可以存储属于同一国家的多个城市的数据。手动创建
如何选择分区列和粒度
  • 分区键由一个或多个分区列组成。选择合适的分区列可以有效地减少查询期间扫描的数据量。在大多数业务系统中,通常采用基于时间的分区来解决因删除过期数据而引起的某些问题,并方便对冷热数据进行分层存储管理。在这种情况下,您可以使用表达式分区或范围分区,并将时间列指定为分区列。此外,如果经常基于 ENUM 值查询和管理数据,则可以使用表达式分区或列表分区,并将包含这些值的列指定为分区列。
  • 在选择分区粒度时,您需要考虑数据量、查询模式和数据管理粒度。
    • 示例 1:如果表中的每月数据量很小,则按月分区可以减少与按天分区相比的元数据量,从而减少元数据管理和调度的资源消耗。
    • 示例 2:如果表中的每月数据量很大,并且查询主要请求某些天的数据,则按天分区可以有效地减少查询期间扫描的数据量。
    • 示例 3:如果数据需要按天过期,建议按天分区。

分桶

分桶方法将分区划分为多个桶。桶中的数据称为 Tablet。

支持的分桶方法包括随机分桶(自 v3.1 起)和哈希分桶

  • 随机分桶:在创建表或添加分区时,您无需设置分桶键。分区中的数据随机分布到不同的桶中。

  • 哈希分桶:在创建表或添加分区时,您需要指定分桶键。同一分区中的数据根据分桶键的值划分为多个桶,并且分桶键中具有相同值的行将分布到相应且唯一的桶中。

桶数:默认情况下,StarRocks 自动设置桶数(自 v2.5.7 起)。您也可以手动设置桶数。有关更多信息,请参阅确定桶数

创建和管理分区

创建分区

注意

StarRocks 的共享数据模式自 v3.1.0 起支持时间函数表达式,自 v3.1.1 起支持列表达式。

自 v3.0 起,StarRocks 支持表达式分区(以前称为自动分区),它更加灵活且易于使用。这种分区方法适用于大多数场景,例如基于连续日期范围或 ENUM 值查询和管理数据。

您只需在创建表时配置分区表达式,StarRocks 将在数据加载期间自动创建分区。您不再需要手动预先创建大量分区,也不需要配置动态分区属性。

从 v3.4 开始,表达式分区得到了进一步优化,统一了所有分区策略并支持更复杂的解决方案。在大多数情况下建议使用它,并且将在未来的版本中替换其他分区策略。

示例 1:使用带有 DATETIME 列的简单时间函数表达式。

CREATE TABLE site_access(
event_day DATETIME NOT NULL,
site_id INT DEFAULT '10',
city_code VARCHAR(100),
user_name VARCHAR(32) DEFAULT '',
pv BIGINT DEFAULT '0'
)
DUPLICATE KEY(event_day, site_id, city_code, user_name)
PARTITION BY time_slice(event_day, INTERVAL 7 day)
DISTRIBUTED BY HASH(event_day, site_id)

示例 2:使用带有多个列的列表达式。

CREATE TABLE t_recharge_detail1 (
id bigint,
user_id bigint,
recharge_money decimal(32,2),
city varchar(20) not null,
dt varchar(20) not null
)
DUPLICATE KEY(id)
PARTITION BY dt,city
DISTRIBUTED BY HASH(`id`);

示例 3:使用带有 Unix 时间戳列的复杂时间函数表达式。

CREATE TABLE orders (
ts BIGINT NOT NULL,
id BIGINT NOT NULL,
city STRING NOT NULL
)
PARTITION BY from_unixtime(ts,'%Y%m%d');

示例 4:使用时间函数表达式和列表达式的混合表达式。

CREATE TABLE orders (
ts BIGINT NOT NULL,
id BIGINT NOT NULL,
city STRING NOT NULL
)
PARTITION BY from_unixtime(ts,'%Y%m%d'), city;

范围分区

范围分区适用于存储简单的连续数据,例如时间序列数据或连续数值数据。范围分区适用于基于连续日期/数值范围频繁查询的数据。此外,它还可以应用于某些特殊情况下,其中历史数据需要按月分区,而最近的数据需要按天分区。

您需要显式定义数据分区列,并建立分区和分区列值范围之间的映射关系。在数据加载期间,StarRocks 会根据数据分区列值所属的范围将数据分配到相应的分区。

至于分区列的数据类型,在 v3.3.0 之前,范围分区仅支持日期和整数类型的分区列。自 v3.3.0 起,可以使用三个特定的时间函数作为分区列。在显式定义分区和分区列值范围之间的映射关系时,您需要首先使用特定的时间函数将时间戳或字符串的分区列值转换为日期值,然后根据转换后的日期值划分分区。

info
  • 如果分区列值为时间戳,则在划分分区时,您需要使用 from_unixtime 或 from_unixtime_ms 函数将时间戳转换为日期值。当使用 from_unixtime 函数时,分区列仅支持 INT 和 BIGINT 类型。当使用 from_unixtime_ms 函数时,分区列仅支持 BIGINT 类型。
  • 如果分区列值为字符串(STRING、VARCHAR 或 CHAR 类型),则在划分分区时,您需要使用 str2date 函数将字符串转换为日期值。
手动创建分区

定义每个分区和分区列值范围之间的映射关系。

  • 分区列为日期类型。

    CREATE TABLE site_access(
    event_day DATE,
    site_id INT,
    city_code VARCHAR(100),
    user_name VARCHAR(32),
    pv BIGINT SUM DEFAULT '0'
    )
    AGGREGATE KEY(event_day, site_id, city_code, user_name)
    PARTITION BY RANGE(event_day)(
    PARTITION p1 VALUES LESS THAN ("2020-01-31"),
    PARTITION p2 VALUES LESS THAN ("2020-02-29"),
    PARTITION p3 VALUES LESS THAN ("2020-03-31")
    )
    DISTRIBUTED BY HASH(site_id);
  • 分区列为整数类型。

    CREATE TABLE site_access(
    datekey INT,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT SUM DEFAULT '0'
    )
    AGGREGATE KEY(datekey, site_id, city_code, user_name)
    PARTITION BY RANGE (datekey) (
    PARTITION p1 VALUES LESS THAN ("20200131"),
    PARTITION p2 VALUES LESS THAN ("20200229"),
    PARTITION p3 VALUES LESS THAN ("20200331")
    )
    DISTRIBUTED BY HASH(site_id);
  • 三个特定的时间函数可以用作分区列(自 v3.3.0 起支持)。

    在显式定义分区和分区列值范围之间的映射关系时,您可以使用特定的时间函数将时间戳或字符串的分区列值转换为日期值,然后根据转换后的日期值划分分区。

    -- A 10-digit timestamp accurate to the second, for example, 1703832553.
    CREATE TABLE site_access(
    event_time bigint,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT SUM DEFAULT '0'
    )
    AGGREGATE KEY(event_time, site_id, city_code, user_name)
    PARTITION BY RANGE(from_unixtime(event_time)) (
    PARTITION p1 VALUES LESS THAN ("2021-01-01"),
    PARTITION p2 VALUES LESS THAN ("2021-01-02"),
    PARTITION p3 VALUES LESS THAN ("2021-01-03")
    )
    DISTRIBUTED BY HASH(site_id)
    ;

    -- A 13-digit timestamp accurate to the millisecond, for example, 1703832553219.
    CREATE TABLE site_access(
    event_time bigint,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT SUM DEFAULT '0'
    )
    AGGREGATE KEY(event_time, site_id, city_code, user_name)
    PARTITION BY RANGE(from_unixtime_ms(event_time))(
    PARTITION p1 VALUES LESS THAN ("2021-01-01"),
    PARTITION p2 VALUES LESS THAN ("2021-01-02"),
    PARTITION p3 VALUES LESS THAN ("2021-01-03")
    )
    DISTRIBUTED BY HASH(site_id);
动态分区

动态分区相关的属性在创建表时配置。StarRocks 会自动提前创建新分区并删除过期的分区以确保存储数据的时效性,从而实现对分区的生存时间 (TTL) 管理。

与表达式分区提供的自动创建分区能力不同,动态分区只能根据属性定期创建新分区。如果新数据不属于这些分区,则加载作业会返回错误。但是,表达式分区提供的自动创建分区能力始终可以根据加载的数据创建相应的新的分区。

批量创建多个分区

可以在创建表时和创建表后批量创建多个分区。您可以在 START()END() 中指定批量创建的所有分区的开始和结束时间,并在 EVERY() 中指定分区增量值。但是,请注意分区的范围是左闭右开的,包括开始时间但不包括结束时间。分区的命名规则与动态分区相同。

  • 分区列为日期类型。

    当分区列为日期类型时,在创建表时,您可以使用 START()END() 指定批量创建的所有分区的开始日期和结束日期,并使用 EVERY(INTERVAL xxx) 指定两个分区之间的增量间隔。目前,间隔粒度支持 HOUR(自 v3.0 起)、DAYWEEKMONTHYEAR

    在以下示例中,批量创建的分区从 2021-01-01 开始,到 2021-01-04 结束,分区增量为一天

    CREATE TABLE site_access (
    datekey DATE,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT DEFAULT '0'
    )
    DUPLICATE KEY(datekey, site_id, city_code, user_name)
    PARTITION BY RANGE (datekey) (
    START ("2021-01-01") END ("2021-01-04") EVERY (INTERVAL 1 DAY)
    )
    DISTRIBUTED BY HASH(site_id);

    它等效于在 CREATE TABLE 语句中使用以下 PARTITION BY 子句

    PARTITION BY RANGE (datekey) (
    PARTITION p20210101 VALUES [('2021-01-01'), ('2021-01-02')),
    PARTITION p20210102 VALUES [('2021-01-02'), ('2021-01-03')),
    PARTITION p20210103 VALUES [('2021-01-03'), ('2021-01-04'))
    )
  • 分区列为整数类型。

    当分区列的数据类型为 INT 时,您可以在 STARTEND 中指定分区范围,并在 EVERY 中定义增量值。示例

    注意

    START()END() 中的分区列值需要用双引号括起来,而 EVERY() 中的增量值不需要用双引号括起来。

    在以下示例中,所有分区的范围从 1 开始,到 5 结束,分区增量为 1

    CREATE TABLE site_access (
    datekey INT,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT DEFAULT '0'
    )
    DUPLICATE KEY(datekey, site_id, city_code, user_name)
    PARTITION BY RANGE (datekey) (
    START ("1") END ("5") EVERY (1)
    )
    DISTRIBUTED BY HASH(site_id);

    它等效于在 CREATE TABLE 语句中使用以下 PARTITION BY 子句

    PARTITION BY RANGE (datekey) (
    PARTITION p1 VALUES [("1"), ("2")),
    PARTITION p2 VALUES [("2"), ("3")),
    PARTITION p3 VALUES [("3"), ("4")),
    PARTITION p4 VALUES [("4"), ("5"))
    )
  • 三个特定的时间函数可以用作分区列(自 v3.3.0 起支持)。

    在显式定义分区和分区列值范围之间的映射关系时,您可以使用特定的时间函数将时间戳或字符串的分区列值转换为日期值,然后根据转换后的日期值划分分区。

    -- A 10-digit timestamp accurate to the second, for example, 1703832553.
    CREATE TABLE site_access(
    event_time bigint,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT DEFAULT '0'
    )
    PARTITION BY RANGE(from_unixtime(event_time)) (
    START ("2021-01-01") END ("2021-01-10") EVERY (INTERVAL 1 DAY)
    )
    DISTRIBUTED BY HASH(site_id);
    -- A 13-digit timestamp accurate to the milliseconds, for example, 1703832553219.
    CREATE TABLE site_access(
    event_time bigint,
    site_id INT,
    city_code SMALLINT,
    user_name VARCHAR(32),
    pv BIGINT DEFAULT '0'
    )
    PARTITION BY RANGE(from_unixtime_ms(event_time))(
    START ("2021-01-01") END ("2021-01-10") EVERY (INTERVAL 1 DAY)
    )
    DISTRIBUTED BY HASH(site_id);

列表分区(自 v3.1 起)

列表分区适用于加速查询和高效管理基于枚举值的数据。它特别适用于一个分区需要包含分区列中不同值的数据的场景。例如,如果您经常基于国家和城市查询和管理数据,则可以使用此分区方法并选择 city 列作为分区列。在这种情况下,一个分区可以包含属于一个国家的各个城市的数据。

StarRocks 根据每个分区的预定义值列表的显式映射将数据存储在相应的分区中。

管理分区

添加分区

对于范围分区和列表分区,您可以手动添加新分区以存储新数据。但是对于表达式分区,由于分区是在数据加载期间自动创建的,因此您无需执行此操作。

以下语句向表 site_access 添加一个新分区以存储新月份的数据

ALTER TABLE site_access
ADD PARTITION p4 VALUES LESS THAN ("2020-04-30")
DISTRIBUTED BY HASH(site_id);

删除分区

以下语句从表 site_access 中删除分区 p1

注意

此操作不会立即删除分区中的数据。数据会保留在回收站中一段时间(默认为一天)。如果分区被错误地删除,您可以使用 RECOVER 命令恢复分区及其数据。

ALTER TABLE site_access
DROP PARTITION p1;

恢复分区

以下语句将分区 p1 及其数据恢复到表 site_access

RECOVER PARTITION p1 FROM site_access;

查看分区

以下语句返回表 site_access 中所有分区的详细信息。

SHOW PARTITIONS FROM site_access;

配置分桶

随机分桶(自 v3.1 起)

StarRocks 将分区中的数据随机分布到所有桶中。它适用于数据量小且对查询性能要求相对较低的场景。如果您不设置分桶方法,StarRocks 默认使用随机分桶并自动设置桶数。

但是,请注意,如果您查询大量数据并且经常使用某些列作为过滤条件,则随机分桶提供的查询性能可能不是最佳的。在这种情况下,建议使用哈希分桶。当这些列用作查询的过滤条件时,只需要扫描和计算查询命中的少量桶中的数据,这可以显着提高查询性能。

限制

  • 您只能使用随机分桶创建 Duplicate Key 表。
  • 您不能指定随机分桶的表属于Colocation Group
  • Spark Load 不能用于将数据加载到随机分桶的表中。

在以下 CREATE TABLE 示例中,未使用 DISTRIBUTED BY xxx 语句,因此 StarRocks 默认使用随机分桶,并自动设置桶数。

CREATE TABLE site_access1(
event_day DATE,
site_id INT DEFAULT '10',
pv BIGINT DEFAULT '0' ,
city_code VARCHAR(100),
user_name VARCHAR(32) DEFAULT ''
)
DUPLICATE KEY(event_day,site_id,pv);

但是,如果您熟悉 StarRocks 的分桶机制,您也可以在创建带有随机分桶的表时手动设置桶数。

CREATE TABLE site_access2(
event_day DATE,
site_id INT DEFAULT '10',
pv BIGINT DEFAULT '0' ,
city_code VARCHAR(100),
user_name VARCHAR(32) DEFAULT ''
)
DUPLICATE KEY(event_day,site_id,pv)
DISTRIBUTED BY RANDOM BUCKETS 8; -- manually set the number of buckets to 8

哈希分桶

StarRocks 可以使用哈希分桶,根据分桶键和桶数将分区中的数据细分为多个桶。在哈希分桶中,哈希函数将数据的分桶键值作为输入,并计算哈希值。数据根据哈希值和桶之间的映射关系存储在相应的桶中。

优点

  • 提高查询性能:具有相同分桶键值的行存储在同一个桶中,从而减少查询期间扫描的数据量。

  • 均匀的数据分布:通过选择具有较高基数(大量唯一值)的列作为分桶键,可以将数据更均匀地分布在各个桶中。

如何选择分桶列

我们建议您选择满足以下两个要求的列作为分桶列。

  • 高基数列,例如 ID
  • 查询中经常用作过滤器的列

但是,如果没有列满足这两个要求,您需要根据查询的复杂性确定分桶列。

  • 如果查询很复杂,建议选择高基数列作为分桶列,以确保数据尽可能均匀地分布在所有桶中,并提高集群资源利用率。
  • 如果查询相对简单,建议选择查询中经常用作过滤条件的列作为分桶列,以提高查询效率。

如果使用一个分桶列无法将分区数据均匀地分布到所有桶中,则可以选择多个分桶列。请注意,建议使用的列数不超过 3 个。

注意事项

  • 创建表时,必须指定分桶列.
  • 分桶列的数据类型必须是 INTEGER、DECIMAL、DATE/DATETIME 或 CHAR/VARCHAR/STRING。
  • 自 3.2 起,可以使用 ALTER TABLE 在创建表后修改分桶列。

示例

在以下示例中,site_access 表是使用 site_id 作为分桶列创建的。此外,当查询 site_access 表中的数据时,数据通常按站点过滤。使用 site_id 作为分桶键可以在查询期间修剪大量不相关的桶。

CREATE TABLE site_access(
event_day DATE,
site_id INT DEFAULT '10',
city_code VARCHAR(100),
user_name VARCHAR(32) DEFAULT '',
pv BIGINT SUM DEFAULT '0'
)
AGGREGATE KEY(event_day, site_id, city_code, user_name)
PARTITION BY RANGE(event_day)
(
PARTITION p1 VALUES LESS THAN ("2020-01-31"),
PARTITION p2 VALUES LESS THAN ("2020-02-29"),
PARTITION p3 VALUES LESS THAN ("2020-03-31")
)
DISTRIBUTED BY HASH(site_id);

假设表 site_access 的每个分区有 10 个桶。在以下查询中,10 个桶中有 9 个被修剪掉,因此 StarRocks 只需要扫描 site_access 表中 1/10 的数据

select sum(pv)
from site_access
where site_id = 54321;

但是,如果 site_id 分布不均匀,并且大量查询仅请求少数站点的数据,则仅使用一个分桶列可能会导致严重的数据倾斜,从而导致系统性能瓶颈。在这种情况下,您可以使用分桶列的组合。例如,以下语句使用 site_idcity_code 作为分桶列。

CREATE TABLE site_access
(
site_id INT DEFAULT '10',
city_code SMALLINT,
user_name VARCHAR(32) DEFAULT '',
pv BIGINT SUM DEFAULT '0'
)
AGGREGATE KEY(site_id, city_code, user_name)
DISTRIBUTED BY HASH(site_id,city_code);

实际上,您可以根据您的业务特征使用一个或两个分桶列。使用一个分桶列 site_id 对短查询非常有益,因为它减少了节点之间的数据交换,从而提高了集群的整体性能。另一方面,采用两个分桶列 site_idcity_code 对长查询有利,因为它可以利用分布式集群的整体并发性来显着提高性能。

注意

  • 短查询涉及扫描少量数据,并且可以在单个节点上完成。
  • 长查询涉及扫描大量数据,并且可以通过在分布式集群中的多个节点上并行扫描来显着提高其性能。

设置桶数

桶反映了数据文件在 StarRocks 中的实际组织方式。

创建表时

  • 自动设置桶数(推荐)

    自 v2.5.7 起,StarRocks 支持根据机器资源和分区的数据量自动设置桶数。

    提示

    如果一个分区的原始数据大小超过 100 GB,我们建议您使用方法 2 手动配置 Bucket 数量。

    示例

    CREATE TABLE site_access (
    site_id INT DEFAULT '10',
    city_code SMALLINT,
    user_name VARCHAR(32) DEFAULT '',
    event_day DATE,
    pv BIGINT SUM DEFAULT '0')
    AGGREGATE KEY(site_id, city_code, user_name,event_day)
    PARTITION BY date_trunc('day', event_day)
    DISTRIBUTED BY HASH(site_id,city_code); -- do not need to set the number of buckets
  • 手动设置 Bucket 数量

    自 v2.4.0 版本起,StarRocks 支持在查询期间使用多线程并行扫描 Tablet,从而降低扫描性能对 Tablet 数量的依赖。我们建议每个 Tablet 包含约 10 GB 的原始数据。如果您打算手动设置 Bucket 数量,您可以估计表中每个分区的数据量,然后确定 Tablet 的数量。

    要启用 Tablet 上的并行扫描,请确保为整个系统全局设置 enable_tablet_internal_parallel 参数为 TRUE (SET GLOBAL enable_tablet_internal_parallel = true;)。

    CREATE TABLE site_access (
    site_id INT DEFAULT '10',
    city_code SMALLINT,
    user_name VARCHAR(32) DEFAULT '',
    event_day DATE,
    pv BIGINT SUM DEFAULT '0')
    AGGREGATE KEY(site_id, city_code, user_name,event_day)
    PARTITION BY date_trunc('day', event_day)
    DISTRIBUTED BY HASH(site_id,city_code) BUCKETS 30;
    -- Suppose the amount of raw data that you want to load into a partition is 300 GB.
    -- Because we recommend that each tablet contain 10 GB of raw data, the number of buckets can be set to 30.
    DISTRIBUTED BY HASH(site_id,city_code) BUCKETS 30;

创建表之后

  • 自动设置桶数(推荐)

    自 v2.5.7 起,StarRocks 支持根据机器资源和分区的数据量自动设置桶数。

    提示

    如果一个分区的原始数据大小超过 100 GB,我们建议您使用方法 2 手动配置 Bucket 数量。

    -- Automatically set the number of buckets for all partitions.
    ALTER TABLE site_access DISTRIBUTED BY HASH(site_id,city_code);

    -- Automatically set the number of buckets for specific partitions.
    ALTER TABLE site_access PARTITIONS (p20230101, p20230102)
    DISTRIBUTED BY HASH(site_id,city_code);

    -- Automatically set the number of buckets for new partitions.
    ALTER TABLE site_access ADD PARTITION p20230106 VALUES [('2023-01-06'), ('2023-01-07'))
    DISTRIBUTED BY HASH(site_id,city_code);
  • 手动设置 Bucket 数量

    您也可以手动指定 Bucket 数量。要计算分区的 Bucket 数量,您可以参考在创建表时手动设置 Bucket 数量的方法,如上所述

    -- Manually set the number of buckets for all partitions 
    ALTER TABLE site_access
    DISTRIBUTED BY HASH(site_id,city_code) BUCKETS 30;
    -- Manually set the number of buckets for specific partitions.
    ALTER TABLE site_access
    partitions p20230104
    DISTRIBUTED BY HASH(site_id,city_code) BUCKETS 30;
    -- Manually set the number of buckets for new partitions.
    ALTER TABLE site_access
    ADD PARTITION p20230106 VALUES [('2023-01-06'), ('2023-01-07'))
    DISTRIBUTED BY HASH(site_id,city_code) BUCKETS 30;

查看 Bucket 数量

创建表后,您可以执行 SHOW PARTITIONS 来查看 StarRocks 为每个分区设置的 Bucket 数量。配置了 Hash Bucketing 的表每个分区的 Bucket 数量是固定的。

info
  • 对于配置了 Random Bucketing 并启用了按需动态增加 Bucket 数量的表,每个分区的 Bucket 数量会动态增加。因此,返回的结果会显示每个分区的当前 Bucket 数量。
  • 对于这种表类型,分区内的实际层次结构如下:分区 > 子分区 > Bucket。要增加 Bucket 数量,StarRocks 实际上是添加一个新的子分区,其中包含一定数量的 Bucket。因此,SHOW PARTITIONS 语句可能会返回多个具有相同分区名称的数据行,这些行显示同一分区内子分区的信息。

创建表后优化数据分布 (自 3.2 版本起)

注意

StarRocks 的 Shared-data 模式目前不支持此功能。

随着业务场景中查询模式和数据量的演变,在创建表时指定的配置(例如 Bucketing 方法、Bucket 数量和排序键)可能不再适合新的业务场景,甚至可能导致查询性能下降。此时,您可以使用 ALTER TABLE 修改 Bucketing 方法、Bucket 数量和排序键以优化数据分布。例如

  • 当分区内的数据量显著增加时,增加 Bucket 数量

    当分区内的数据量比以前显著增加时,有必要修改 Bucket 数量,以使 Tablet 大小通常保持在 1 GB 到 10 GB 的范围内。

  • 修改 Bucketing Key 以避免数据倾斜

    当当前的 Bucketing Key 可能导致数据倾斜时(例如,仅将 k1 列配置为 Bucketing Key),有必要指定更合适的列或将其他列添加到 Bucketing Key。例如

    ALTER TABLE t DISTRIBUTED BY HASH(k1, k2) BUCKETS 20;
    -- When the StarRocks's version is 3.1 or later, and the table is Duplicate Key table, you can consider directly using the system's default bucketing settings, that is, random bucketing and the number of buckets automatically set by StarRocks.
    ALTER TABLE t DISTRIBUTED BY RANDOM;
  • 由于查询模式的变化而调整排序键

    如果业务查询模式发生显著变化,并且使用其他列作为条件列,则调整排序键可能是有益的。例如

    ALTER TABLE t ORDER BY k2, k1;

有关更多信息,请参见 ALTER TABLE