当单表数据量过大导致查询缓慢,或初期设定的分区策略不合理引发数据热点时,原有的表结构可能成为业务瓶颈。为解决此类问题,PolarDB分布式版提供了在线(Online)变更表类型和分区策略的功能。可以在不中断业务(不锁表、不阻塞DML)的情况下,对表进行数据重分布,实现单表、广播表、分区表之间的相互转换,或调整现有分区表的分区键、分区算法,以优化数据布局,提升数据库整体性能和可扩展性。
此操作属于重型DDL任务,其本质是在线进行全量数据迁移和重分布。
执行期间会消耗大量的CPU、IO和网络资源,可能对实例性能产生影响,且耗时与数据量成正比。
建议在业务低峰期执行,并配合使用任务管理命令进行监控。
适用范围
执行变更前,需确保环境满足以下条件。
数据库模式:仅适用于AUTO模式数据库。
实例版本:仅支持PolarDB-X 2.0,且内核小版本需为
5.4.13及以上版本。全局二级索引(GSI):仅支持PolarDB-X 2.0,且内核小版本需为
5.4.14及以上版本对带有GSI的分区表进行分区变更。变更过程中,GSI的数据会同步进行重分布。
工作原理
在线DDL:所有变更操作均以在线方式执行,期间不锁定原表,DML/SELECT操作均可正常进行,保障业务连续性。
数据重分布:变更表类型或分区策略的核心是数据的物理迁移。例如:
将单表转为分区表时,数据会从单个数据节点(DN)分散到多个DN。
变更分区键时,数据会根据新的分区策略在DN间重新平衡。此过程是资源消耗的主要原因。
原子性与可回滚:整个DDL任务具备原子性。如果任务因唯一键冲突、磁盘空间不足等原因执行失败,系统会确保原表数据完好无损,业务不受影响。失败的任务可通过 CANCEL DDL命令回滚该任务。
变更表类型
PolarDB分布式版支持单表、广播表和分区表三种类型,可根据业务场景的变化在它们之间进行在线转换。详细信息,请参见CREATE TABLE(AUTO模式)。
变更表类型时,如果原表为主键分区表(即分区键与主键一致),在将其变更为普通表后,该表将不再具备主键分区表的特性,例如自动分区策略或索引转换规则。详细信息,请参见AUTO模式下的主键拆分。
将单表或广播表变更为分区表
此场景适用于单表数据量持续增长,已成为或即将成为性能瓶颈,需要将其水平拆分以提升扩展性和查询性能。
语法说明
使用ALTER TABLE语句并指定新的分区策略。关于partition_options的详细语法,请参见分区表。
ALTER TABLE table_name PARTITION BY partition_options;示例
创建一个示例表
t_order。CREATE TABLE t_order ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, `seller_id` varchar(20) DEFAULT NULL, `order_snapshot` longtext DEFAULT NULL, `order_detail` longtext DEFAULT NULL, PRIMARY KEY (`id`), KEY `l_i_order` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;因业务发展导致单表
t_order数据量剧增,现决定将其变更为以order_id为分区键的分区表。-- 将单表 t_order 变更为以 order_id 为分区键的KEY分区表 ALTER TABLE t_order PARTITION BY KEY(`order_id`); -- 也可以在变更的同时指定分区数量 ALTER TABLE t_order PARTITION BY KEY(`order_id`) PARTITIONS 8;
将分区表或单表变更为广播表
该场景适用于数据量较小且几乎不增长的表,但这些表频繁与其他大型表进行关联查询(JOIN),例如配置表和字典表。通过将表数据复制到每个数据节点(DN),可以消除跨库JOIN所带来的网络开销,从而提升关联查询的性能。
语法说明
使用 ALTER TABLE语句并指定BROADCAST子句。
ALTER TABLE table_name BROADCAST;广播表的数据会在所有DN节点上存有副本,会占用更多存储空间。
示例
创建一个示例表
t_order_1。CREATE TABLE t_order_1 ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, `seller_id` varchar(20) DEFAULT NULL, `order_snapshot` longtext DEFAULT NULL, `order_detail` longtext DEFAULT NULL, PRIMARY KEY (`id`), KEY `l_i_order` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;将
t_order_1表变更为广播表。ALTER TABLE t_order_1 BROADCAST;
将分区表或广播表变更为单表
此场景适用于数据量较小且无需进行水平扩展的表。将表的数据集中到单个数据节点(DN)上,以简化表结构。
语法说明
使用ALTER TABLE语句并指定SINGLE子句。
ALTER TABLE table_name SINGLE;将分区表变更为单表时,所有分片的数据都会汇聚到同一个DN节点。需确保目标节点的磁盘空间充足,避免因空间不足导致操作失败。
示例
创建一个示例表
t_order_2。CREATE TABLE t_order_2 ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, `seller_id` varchar(20) DEFAULT NULL, `order_snapshot` longtext DEFAULT NULL, `order_detail` longtext DEFAULT NULL, PRIMARY KEY (`id`), KEY `l_i_order` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY KEY(`order_id`) PARTITIONS 8;将
t_order_2表变更为单表。ALTER TABLE t_order_2 SINGLE;
变更分区表的分区策略
当现有的分区策略无法满足业务需求时,例如由于分区键选择不当导致的数据倾斜,或业务查询模式的变化,可以在线调整分区策略。通过对分区键、分区函数或分区数量进行修改,重新优化数据的物理分布,以解决数据热点问题,适应新的业务模型。
语法说明
使用ALTER TABLE语句并指定新的分区策略。
ALTER TABLE tbl_name PARTITION BY new_partition_options;如果原表是主键分区表(即分区键与主键一致),在变更分区策略后,若新的分区键不再是主键,该表将不再具备主键分区表的特性(如自动创建分区等)。详细信息,请参见AUTO模式下的主键拆分。
在变更分区策略后,如果主键列未包含全部分区列,则该主键为Local主键,只能保证分区内唯一,无法保证全局唯一。详细信息,请参见主键与唯一键(AUTO模式)。
示例
变更分区键
创建一个t_order_3表当前按order_id分区,但多数查询基于buyer_id,导致跨分片查询较多。现需要将分区键变更为buyer_id,并将分区数设定为16。
原表结构。
CREATE TABLE t_order_3 ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY KEY(`order_id`) PARTITIONS 8;执行变更。
ALTER TABLE t_order_3 PARTITION BY KEY(buyer_id) PARTITIONS 16;变更后表结构:系统会自动创建新的分区键索引
auto_shard_key_buyer_id。SHOW FULL CREATE TABLE t_order_3;+-----------+-----------------------------------------------------------------------+ | Table | Create Table | +-----------+-----------------------------------------------------------------------+ | t_order_3 | CREATE TABLE `t_order_3` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`), LOCAL KEY `auto_shard_key_buyer_id` USING BTREE (`buyer_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 DEFAULT COLLATE = utf8mb4_0900_ai_ci PARTITION BY KEY(`buyer_id`) PARTITIONS 16 /* tablegroup = `tg12` */ | +-----------+---------------------------------------------------------------------+
变更分区策略
创建一个t_order_4表目前根据id进行RANGE分区,但大多数查询是基于order_id和buyer_id。因此,需要将其变更为以order_id和buyer_id作为分区键的KEY分区,并将分区数设定为16。
原表结构。
CREATE TABLE t_order_4 ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY RANGE(`id`) ( PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN (1000), PARTITION P3 VALUES LESS THAN MAXVALUE );执行变更。
ALTER TABLE t_order_4 PARTITION BY KEY(order_id, buyer_id) PARTITIONS 16;变更后表结构:系统会自动创建新的分区键索引
auto_shard_key_order_id_buyer_id。SHOW FULL CREATE TABLE t_order_4;+-----------+--------------------------------------------------------------------------------+ | Table | Create Table | +-----------+--------------------------------------------------------------------------------+ | t_order_4 | CREATE TABLE `t_order_4` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`), LOCAL KEY `auto_shard_key_order_id_buyer_id` USING BTREE (`order_id`, `buyer_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb3 PARTITION BY KEY(`order_id`,`buyer_id`) PARTITIONS 16 /* tablegroup = `tg15` */ | +-----------+------------------------------------------------------------------------------+
增加分区数量
随着数据量增长,需要增加分区数以分散数据。
原表结构。
CREATE TABLE t_order_5 ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY KEY(`order_id`) PARTITIONS 8;执行变更。
ALTER TABLE t_order_5 PARTITION BY KEY(order_id) PARTITIONS 128;变更后,分区数将从8个扩展到128个。
SHOW FULL CREATE TABLE t_order_5;+-----------+----------------------------------------------------------+ | Table | Create Table | +-----------+----------------------------------------------------------+ | t_order_4 | CREATE TABLE `t_order_5` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_id` varchar(20) DEFAULT NULL, `buyer_id` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`), LOCAL KEY `auto_shard_key_order_id` USING BTREE (`order_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb3 PARTITION BY KEY(`order_id`) PARTITIONS 128 /* tablegroup = `tg13` */ | +-----------+---------------------------------------------------------+
任务管理与应急处理
对于耗时较长的数据重分布DDL任务,可使用以下命令进行全生命周期管理。
监控任务进度:使用SHOW DDL命令可以查看当前正在执行或历史的DDL任务列表及其状态。
暂停与恢复任务:如果DDL任务对业务高峰期的性能产生较大影响,可以先暂停,待低峰期再恢复。
-- 暂停任务,从 SHOW DDL 的结果中获取 JobId PAUSE DDL <JobId>; -- 恢复任务 CONTINUE DDL <JobId>;终止与回滚任务:如果DDL任务执行失败,或希望主动取消正在执行的任务,可使用CANCEL DDL命令。该操作会回滚所有变更,使表结构和数据恢复到任务开始前的状态。
-- 回滚任务,从 SHOW DDL 的结果中获取 JobId CANCEL DDL <JobId>;
应用于生产环境
执行时机:建议在业务低峰期执行此类操作,以减少对线上业务的潜在性能影响。
容量规划:执行变更前,需评估目标数据节点(DN)的磁盘空间、CPU和IOPS资源是否充足,特别是对于分区表转单表或数据重分布剧烈的场景,避免因资源不足导致任务失败。
操作前备份:尽管DDL任务失败可回滚,但在生产环境执行任何重大变更前,建议完成一次全量数据备份。
验证:任务完成后,可使用
SHOW CREATE TABLE <tablename>查看新的表定义,或使用SHOW TOPOLOGY查看新的数据分片拓扑。