DDL操作指南

本文介绍了PolarDB-X中DDL的执行逻辑和执行方式。

背景知识

PolarDB-X的架构如下:

image.png

PolarDB-X在执行DDL时,几乎各个组件都需要参与,以保证DDL的正确性。

  • 元数据服务节点(GMS)维护了Table/Schema、Statistic等元数据信息;

  • 计算节点(CN)提供了分布式DDL执行、全局索引维护等能力;

  • 存储节点(DN)维护了所有Table/Schema的物理数据,并且具有DDL下推能力(例如ALTER TABLE等DDL操作的下推)。

为了便于说明,本文将用户发送到PolarDB-X实例(由计算节点接收)的DDL称为用户DDL,而在用户DDL执行过程中由计算节点下推发送到存储节点的DDL称为物理 DDL。

DDL执行方式

PolarDB-X中,DDL按照执行方式主要分为两类,物理执行的DDL和逻辑执行的DDL。

物理执行

物理执行的DDL指的是主要依赖存储节点物理DDL下推能力完成的DDL。物理执行的DDL在执行过程中,计算节点仅维护元数据信息的变化,真正的结构变更由存储节点完成。例如Create Table、Drop Table、Create Local Index以及常用的Alter Table等。

原子性

PolarDB-X中,一张逻辑表往往对应了多个物理表(分片),且这些分片往往分布在多个存储节点中。在对一张逻辑表做DDL变更时,如果是物理执行方式,那么计算节点会将用户DDL先转换为物理DDL,然后下推到相应的存储节点执行,并且记录各个分片的完成情况,在所有分片完成物理DDL变更后,计算节点再进行元数据的最终变更。

物理执行的DDL在执行过程中是可以并发的,因此在执行过程中,计算节点不仅会记录各个分片的执行情况,还需要保证所有分片变更的原子性,确保所有分片可以一起完成变更,详情请参见DDL原子性

执行算法

物理执行的DDL在执行过程中是否锁表(允许并发DML)、是否需要重建表(持续时间长短)以及是否仅修改元数据(秒级完成)完全依赖存储节点执行物理DDL的执行算法。

存储节点执行物理DDL的执行算法主要有以下三种:

  • INSTANT算法,仅需修改数据字典中的元数据,不需要修改或复制存量数据,也不需要重建物理表,物理DDL可以秒级完成;

  • INPLACE算法,物理表中的数据需要复制和重建,但是复制和重建都在存储引擎内部完成,通常允许并发读写访问,对业务影响较小;

  • COPY算法,需要将物理表中所有的数据复制到新表中,数据复制期间会阻塞所有写操作(锁表),对业务影响较大。

不同的DDL支持的执行算法会有所不同,详情请参见Online DDL

逻辑执行

逻辑执行的DDL指的是主要依赖计算节点Online Schema Change能力完成的DDL。逻辑执行通常需要经历创建新的临时表,拷贝存量数据,同步增量数据,并进行元数据切换等步骤,一般执行时间较长,但是全程Online无需锁表,例如:Create Global Index、Drop Global Index、Online Modify Column、Add Primary Key以及分区变更相关DDL等;也存在一些逻辑执行的DDL可以通过直接修改元数据并进行同步方式完成,例如:Rename Table、Rename Global Index等。

逻辑执行的DDL通常拥有以下几个特点:

  • 在线变更,无需锁表,对用户业务影响较小;

  • 通常需要重建表,存在数据拷贝,执行时间相对较长;

  • 保证原子性,不会出现部分分片执行成功,部分分片执行失败的情况。

并行度调整

逻辑执行的DDL通常需要拷贝存量数据,这是一个耗时较长的过程,在计算节点和存储节点不存在CPU、IO等瓶颈的情况下,可以调整存量数据回填的并行度以及数据回填的限速,来提升DDL执行效率。

例如,在创建全局二级索引的过程中,主表的存量数据需要回填到全局二级索引表中,如果计算节点和存储节点的CPU、IO等资源都不存在瓶颈,可以调整数据回填的并行度以及数据回填的限速,来提升数据回填的速度。

-- 设置数据回填的全局并行度,默认值为32,根据经验这个值一般无需调整
set global BACKFILL_PARALLELISM = 32;

-- 物理分片数据回填的并行度,默认值为4,物理分片数据量较大时推荐调整
set global PHYSICAL_TABLE_BACKFILL_PARALLELISM = 8;

-- 设置数据回填的限速,默认值为150000 rows/s
set global GSI_BACKFILL_SPEED_LIMITATION = 250000;

由于不同的表结构、拓扑以及数据量都不尽相同,因此除了上面给出的参数外还有一些其他参数可以调整,详情请参见并行DDL

如何判断DDL执行方式

PolarDB-X中,可以通过explain语句来判断DDL的执行方式。如果explain的结果与原本DDL语句类似,则为物理执行的DDL;如果explain的结果中包含类似Create Table语句,则为逻辑执行的DDL。

示例

  • PolarDB-X实例中,创建一张逻辑表t1,其结构如下:

+-------+--------------------------------------------------------------------------+
| Table | Create Table                                                             |
+-------+--------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
        `a` int(11) DEFAULT NULL,
        `b` int(11) DEFAULT NULL
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4                                        |
+-------+--------------------------------------------------------------------------+
  • 使用EXPLAIN语句来判断“给逻辑表t1添加一个局部索引”这个DDL操作是逻辑执行还是物理执行,其执行结果如下,可以看到,执行方式为物理执行。

explain alter table t1 add local index idx(b);
+----------------------------------------------------------------------------------+
| EXECUTION PLAN                                                                   |
+----------------------------------------------------------------------------------+
| ALTER_TABLE( tables="t1", shardCount=16, sql="ALTER TABLE ? ADD INDEX idx (b)" ) |
| EXCLUDE_RESOURCE( wumu.t1, wumu.tg17 )                                           |
| SHARE_RESOURCE( wumu.t1, wumu.tg17 )                                             |
+----------------------------------------------------------------------------------+
  • 使用explain语句来判断“将逻辑表t1的分区算法修改为partition by key(a)”这个DDL操作是逻辑执行还是物理执行,其执行结果如下,可以看到,执行方式为逻辑执行。

explain alter table t1 partition by key(a);
+----------------------------------------------------------------------------------+
| EXECUTION PLAN                                                                   |
+----------------------------------------------------------------------------------+
| CREATE_TABLE( tables="t1_msfg", shardCount=16, sql="CREATE TABLE ? (
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `_drds_implicit_id_` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`_drds_implicit_id_`),
  INDEX `auto_shard_key_a` USING BTREE(`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4" )                                      |
| DROP_TABLE( tables="t1_msfg", shardCount=16, sql="DROP TABLE IF EXISTS ?" )       |
| EXCLUDE_RESOURCE( wumu.t1, wumu.t1_msfg, wumu.tg17 )                              |
| SHARE_RESOURCE( wumu.t1, wumu.t1_msfg, wumu.tg17 )                                |
+-----------------------------------------------------------------------------------+

如何异步执行DDL

PolarDB-X中,默认使用同步的方式执行DDL,与MySQL保持一致。在同步执行DDL时,在执行期间如果连接发生中断可能导致DDL执行被暂停,如果预期DDL执行时间过长,可以考虑使用异步的方式执行DDL。

可以通过在要执行的DDL前添加hint的方式来开启异步执行DDL,示例如下:

/*+TDDL:cmd_extra(PURE_ASYNC_DDL_MODE=true)*/ alter table t1 add global index gsi_a(a) partition by key(a);

更多信息,请参见DDL异步执行语法扩展