@Greptime: 重新分区大表通常是一个迁移项目:新建表、双写、回填TB级历史数据、切换。Gr…

X AI KOLs Timeline 产品

摘要

GreptimeDB v1.1 通过单个 ALTER TABLE 语句引入了对现有表的在线重新分区,消除了数据迁移、双写或应用程序变更的需求。它利用共享对象存储和逻辑分片来更新清单和路由,而无需在节点之间移动数据。

重新分区一个大表通常是一个迁移项目:新建表、双写、回填TB级历史数据、切换。 GreptimeDB v1.1 使其变为一个在线DDL: ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id, area) ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South', device_id >= 100 AND area <= 'East', device_id >= 100 AND area > 'East' ); 为什么它不是数据迁移:数据存在于共享对象存储中,而不是节点本地磁盘。Region 是一个逻辑分片,通过清单引用文件。重新分区更新清单和路由——节点之间零字节移动。 然后使用 SPLIT / MERGE PARTITION 来调整热点,以应对负载变化。 https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table…
查看原文
查看缓存全文

缓存时间: 2026/07/14 14:26

将大表重新分区通常是一个迁移项目:创建新表、双写、回填TB级历史数据、切换流量。

GreptimeDB v1.1 将其变为一个在线 DDL 操作:

ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id, area) (
  device_id < 100 AND area < 'South',
  device_id < 100 AND area >= 'South',
  device_id >= 100 AND area <= 'East',
  device_id >= 100 AND area > 'East'
);

为什么这不是数据迁移:数据存放在共享对象存储中,而非节点本地磁盘。Region 是一个逻辑分片,通过清单(manifest)引用文件。重新分区只需更新清单 + 路由——节点间零字节移动。

然后通过 SPLIT / MERGE PARTITION 来根据负载变化调整热点。

https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table…


为已有表添加分区:GreptimeDB v1.1 的在线重新分区

来源:https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table

你希望在表创建后为其添加分区。过去唯一的办法是重建:创建一个新的分区表、双写、回填历史数据、然后切换流量。GreptimeDB v1.1 让你只需执行一条 ALTER TABLE 即可对已有的无分区表进行分区,无需重建。

分区规则通常在表创建时固定 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#partition-rules-are-usually-fixed-at-table-creation)

在大多数支持分区的数据库中,分区规则必须在创建表时决定,之后很难更改。当数据量小时,单个分片的一张表就足够了,因此这个限制并不明显。一旦数据增长,问题就暴露出来了。

sensor_readings 表为例,创建时没有分区。随着设备数量从几十增长到数千,写入量从每秒几千行攀升到五万行,所有流量都落在同一个 Region 和同一个节点上。该节点成为瓶颈:写延迟上升,查询变慢,CPU 和磁盘接近饱和,而集群中的其他节点却空闲着。

此时你希望添加分区并将负载分散到多个节点,但分区规则却无法再更改。只能走传统的路径:

  1. 创建一张带有新分区规则的新表。
  2. 在应用端同时向新旧两张表双写。
  3. 将旧表的历史数据回填到新表中。
  4. 验证一致性、切换读流量、最后废弃旧表。

迁移 TB 级的历史数据耗时很长,消耗带宽,影响在线负载,并且需要修改应用。因此分区方案通常必须提前规划,后期调整代价高昂。

这正是 GreptimeDB v1.1 填补的空白:你可以对一张已存在且未分区的表在线添加分区。

v1.1:通过一条 DDL 实现在线分区 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#v1-1-online-partitioning-in-a-single-ddl)

执行以下语句:

ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id, area) (
  device_id < 100 AND area < 'South',
  device_id < 100 AND area >= 'South',
  device_id >= 100 AND area <= 'East',
  device_id >= 100 AND area > 'East'
);

执行后,原本集中在单个 Region 的 sensor_readings 表被拆分为四个分区,并调度到四个节点上。负载得以分散,写入吞吐量随节点数扩展。无需新建表、无需双写、无需回填历史数据、无需修改应用代码。

GreptimeDB 在线重新分区概览:从过载的单个 Region,到一条 ALTER TABLE 将负载分布到多个节点,再到通过 SPLIT / MERGE 持续调整。

工作原理:计算与存储分离 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#how-it-works-decoupled-compute-and-storage)

这种能力并非来自 SQL 语法,而是来自底层架构:计算与存储分离设计。

在传统的无共享架构中,每个节点的数据位于其本地磁盘上。重新分区意味着在节点间物理移动数据,将 TB 级的文件从一台机器复制到另一台。这个过程缓慢且消耗资源,这也是许多系统在表创建后不支持更改分区的主要原因之一。

GreptimeDB 将数据存储在共享对象存储(S3 及兼容存储)中,不绑定到任何单个节点的本地磁盘。Region 是一个逻辑分片:它通过清单文件引用对象存储中的数据文件,而非持有数据本身。因此,重新分区是一个元数据操作:更新每个 Region 的清单文件引用,切换到新的分区布局,并重新计算路由。数据本身在节点间从未移动。

GreptimeDB 存储计算分离:在耦合架构中,数据绑定到节点,重新分区意味着移动数据;在 GreptimeDB 的分离存储中,重新分区只是一个元数据切换。这就是计算与存储分离带来的弹性:计算和存储可以独立扩展,分区布局可以随负载变化,而无需在表创建时固定。在本地磁盘架构中,对大表重新分区是耗时数小时的数据迁移。在 GreptimeDB 中,同样的任务是一个在线元数据切换。

重新分区期间写入可能短暂波动。官方建议启用客户端重试,以平滑过渡。

分区之后:拆分与合并 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#after-partitioning-splitting-and-merging)

将无分区表转为分区表只是第一步。数据分布随时间变化,今天均衡的布局明天可能出现热点或冷分区。GreptimeDB 提供两种操作来调整现有分区:SPLIT PARTITION 拆分过热分区以增加写入并发,MERGE PARTITION 合并已变冷、变小的分区以回收资源。

-- 拆分热点分区
ALTER TABLE sensor_readings SPLIT PARTITION (
  device_id < 100 AND area < 'South'
) INTO (
  device_id < 50  AND area < 'South',
  device_id >= 50 AND device_id < 100 AND area < 'South'
);

-- 合并冷分区
ALTER TABLE sensor_readings MERGE PARTITION (
  device_id >= 100 AND area <= 'East',
  device_id >= 100 AND area > 'East'
);

除了基于现有分区列进行拆分外,SPLIT PARTITION ... ON COLUMNS 可以在拆分时引入新的分区列。例如,一张最初仅按 device_id 分区的表,可以后续再按 area 进一步划分:

-- 初始仅按 device_id 分区
ALTER TABLE sensor_readings PARTITION ON COLUMNS (device_id) (
  device_id < 100,
  device_id >= 100
);

-- 在拆分时引入新的分区列 area
ALTER TABLE sensor_readings SPLIT PARTITION (
  device_id < 100
) ON COLUMNS (device_id, area) INTO (
  device_id < 100 AND area < 'South',
  device_id < 100 AND area >= 'South'
);

拆分后,表的分区列变为 (device_id, area)。因此,分区维度本身可以随业务演进,而不仅仅是现有维度内的边界调整。

有关在已有分区表上拆分和合并的完整逐步教程,请参阅配套指南:如何在 GreptimeDB 中在线拆分和合并分区 (https://greptime.com/blogs/2026-03-19-greptimedb-repartition-guide)。

结合初始的 PARTITION ON COLUMNS 分区,这形成了一个完整的流程:从无分区到有分区,再根据负载变化持续调整。

运维循环:诊断、执行、迭代 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#the-operational-loop-diagnose-execute-iterate)

在线重新分区将容量管理转变为可观测、可迭代的循环。

首先诊断哪个 Region 负载较重。将 Region 级统计信息与分区规则结合:

SELECT
  t.table_name,
  r.region_id,
  r.region_number,
  p.partition_name,
  p.partition_description,
  r.written_bytes_since_open,
  r.region_rows
FROM information_schema.region_statistics r
JOIN information_schema.tables t
  ON r.table_id = t.table_id
JOIN information_schema.partitions p
  ON p.table_schema = t.table_schema
  AND p.table_name = t.table_name
  AND p.greptime_partition_id = r.region_id
WHERE t.table_schema = 'public'
  AND t.table_name = 'sensor_readings'
ORDER BY r.written_bytes_since_open DESC
LIMIT 10;

written_bytes_since_open 持续偏高的分区适合拆分。同时,查询 information_schema.region_peers 确认对应节点健康,避免将节点不稳定误判为热点。

除 SQL 外,GreptimeDB 内置的 Grafana 仪表盘 (https://github.com/GreptimeTeam/greptimedb/tree/main/grafana) 现在包含热点板块(热点 Region、Datanode 写负载、数据分布),可以直观地显示热点 Region 和写倾斜的 Datanode,详见 greptimedb#8098 (https://github.com/GreptimeTeam/greptimedb/pull/8098)。

然后执行:在线运行对应的 ALTER TABLE。这会更新元数据,写入可能短暂波动。

最后迭代:观察新的负载分布,根据需要继续拆分热点分区或合并冷分区。

注意事项 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#things-to-keep-in-mind)

在线重新分区依赖于计算与存储分离架构,因此有一些前提条件:

  • 仅在分布式集群中支持。单机部署无法重新分区。
  • 必须使用共享对象存储(如 AWS S3),以便所有 Datanode 都能访问同一份数据。
  • 必须在 Metasrv 和所有 Datanode 上启用 GC。对象存储保存 Region 文件,GC 仅在旧引用释放后才回收文件,这可以防止在重新分区期间意外删除仍在使用的数据。

一些实际细节:

  • SPLITMERGE 的分区参数必须与现有分区规则完全匹配。常见情况为 1 拆 2 和 2 合 1;更复杂的变更可以通过多次拆分和合并完成。
  • 重新分区语句支持异步执行。添加 WITH (WAIT = false) 会立即返回一个 procedure_id,你可以通过 ADMIN procedure_state(procedure_id) 跟踪进度。TIMEOUT 控制整体时间限制,无论 WAIT 为 true 还是 false 均生效。
ALTER TABLE sensor_readings SPLIT PARTITION (
  device_id < 100 AND area < 'South'
) INTO (
  device_id < 50  AND area < 'South',
  device_id >= 50 AND device_id < 100 AND area < 'South'
) WITH (
  TIMEOUT = '5m',
  WAIT = false
);

如果你正在评估 GreptimeDB,这意味着什么 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#what-this-means-if-you-re-evaluating-greptimedb)

如果你正在评估 GreptimeDB 的可扩展性和运维成本,在线重新分区改变了两个层面。

首先是可扩展性。一张表的能力不再受限于创建时的分区决策。一张在线表可以随着数据增长而重新分区和水平扩展,无需停机,无需重建。

其次是运维成本。得益于计算与存储分离,重新分区是一个轻量级的元数据切换,而非 TB 级的数据迁移。分区方案不必在表创建时一次性固定,而是可以根据负载变化持续调整。

企业版:Autopilot 自动负载均衡 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#enterprise-automatic-load-balancing-with-autopilot)

以上所有操作均为手动重新分区:你诊断热点、决定拆分还是合并、并自己执行语句。GreptimeDB 企业版的 Autopilot 实现了这一工作流的自动化。它运行在 Metasrv 内部,持续收集 Datanode 和 Region 的写入统计信息,平滑短期波动,并在满足配置条件时提交调度操作。

Autopilot 包含两种互补策略:

  • Auto Repartition 自动拆分可能成为瓶颈的大 Region 为更小的 Region。它适用于已有分区规则的表。一旦你通过 PARTITION ON COLUMNS 对表进行了分区,后续的拆分可以交给它处理;它不会为完全没有分区规则的表生成分区。
  • Region Balancer 自动在 Datanode 之间迁移热点 Region,以平衡节点间的写负载。

两者共享相同的运行时和集群统计信息,共同保持分区分布和节点负载的均衡,省去手动诊断和决策的工作。你可以通过 plugins.auto_repartitionplugins.region_balancer 等配置选项调整其行为,包括拆分触发比率、每次拆分的最大份数以及冷却期。

延伸阅读 (https://greptime.com/blogs/2026-07-09-greptimedb-v1.1-partition-existing-table#further-reading)

  • 如何在 GreptimeDB 中在线拆分和合并分区 (https://greptime.com/blogs/2026-03-19-greptimedb-repartition-guide):针对已有分区表的分步教程
  • 重新分区文档 (https://docs.greptime.com/user-guide/deployments-administration/manage-data/repartition/):前提条件、热点检测和完整语法
  • ALTER TABLE 参考 (https://docs.greptime.com/reference/sql/alter/#split-or-merge-partitions):重新分区的 SQL 语法细节
  • Autopilot 文档 (https://docs.greptime.com/enterprise/autopilot/overview/):企业版自动重新分区和 Region 均衡器

相似文章