在线DDL
在线DDL支持对正常业务影响较小的情况下进行DDL,减少对业务的影响,提高业务运行的连续性和数据库的可用性。部分在线DDL只需要修改元数据,不涉及重建数据,操作时长较快,对业务影响较小。传统DDL操作若涉及重建数据,例如修改列类型、移动表空间、VACUUM FULL等操作,会对操作的表加长时间的排他锁,阻塞对该表的并发读写操作,影响用户业务运行。阻塞时长与数据量成正比,当数据量较大时,阻塞时长可达数小时、甚至数天。相比之下,在线DDL不会长时间加排他锁,执行中允许对该表的并发读写操作,减少对用户业务运行影响。
- 使用DDL功能时,数据库需正常运行。
使用在线DDL操作过程中进行并发读写操作
- 创建表。
gaussdb=# CREATE TABLE t1(c1 INT,c2 INT); gaussdb=# INSERT INTO t1 VALUES(generate_series(1,10), generate_series(1,10)); -- 查看表格 gaussdb=# \d+ t1 Table "public.t1" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | Has OIDs: no Distribute By: HASH(c1) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off
- 历史版本已支持的在线DDL操作(仅部分示例,全部历史版本支持的在线DDL操作请参见《参考》中“SQL参考 > SQL语法 > Online DDL及其操作”)。
- 在线添加列。
gaussdb=# ALTER TABLE t1 ADD COLUMN c3 integer; ALTER TABLE - 在线删除列。
gaussdb=# ALTER TABLE t1 drop COLUMN c3; ALTER TABLE - 在线重命名表。
gaussdb=# ALTER TABLE t1 RENAME TO t2; ALTER TABLE gaussdb=# ALTER TABLE t2 RENAME TO t1; ALTER TABLE
- 在线添加列。
- 设置ONLINE关键字并进行相关操作。
- 在线修改列类型。
gaussdb=# ALTER TABLE ONLINE t1 ALTER c2 TYPE BIGINT; ALTER TABLE - 在线添加非空约束。
gaussdb=# ALTER TABLE ONLINE t1 ALTER c1 SET NOT NULL; ALTER TABLE - 在线添加检查约束。
gaussdb=# ALTER TABLE ONLINE t1 ADD CONSTRAINT c2_k CHECK(c2 > 0); ALTER TABLE - 在线修改添加唯一约束。
gaussdb=# ALTER TABLE ONLINE t1 ADD UNIQUE(c1); NOTICE: ALTER TABLE / ADD UNIQUE will create implicit index "t1_c1_key" for table "t1" ALTER TABLE - 在线表级移动表空间。
gaussdb=# CREATE TABLESPACE tbs RELATIVE LOCATION 'tablespace1/tbs'; CREATE TABLESPACE gaussdb=# ALTER TABLE ONLINE t1 SET TABLESPACE tbs; ALTER TABLE
- 以上在线DDL操作中,可进行并发读写操作。
gaussdb=# INSERT INTO t1 VALUES(11, 11); INSERT 0 1
- 在线修改列类型。
- 查看表结构。
gaussdb=# \d+ t1 Table "public.t1" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | not null | plain | | c2 | bigint | | plain | | Indexes: "t1_c1_key" UNIQUE CONSTRAINT, ubtree (c1) WITH (storage_type=USTORE) TABLESPACE pg_default Check constraints: "c2_k" CHECK (c2 > 0) Has OIDs: no Tablespace: "tbs" Distribute By: HASH(c1) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off - 使用VACUUM FULL在线回收表空间。
gaussdb=# VACUUM FULL t1 ONLINE; VACUUM
使用分区在线DDL操作过程中进行并发读写操作
- 创建分区表和普通表。
gaussdb=# CREATE TABLE t1(c1 INT,c2 INT) PARTITION BY RANGE (c2) ( PARTITION P1 values less than (5), PARTITION P2 values less than (10), PARTITION P3 values less than (101) ); gaussdb=# INSERT INTO t1 VALUES(generate_series(1,100), generate_series(1,100)); gaussdb=# CREATE TABLE t1_exchange(c1 INT,c2 INT); gaussdb=# INSERT INTO t1_exchange VALUES(generate_series(10,50), generate_series(10,50)); -- 查看表格 gaussdb=# \d+ t1 Table "public.t1" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | Partition By RANGE(c2) Number of partitions: 3 (View pg_partition to check each partition range.) Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off gaussdb=# \d+ t1_exchange Table "public.t1_exchange" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off
- 设置ONLINE关键字并进行相关操作。
- 在线合并分区。
gaussdb=# ALTER TABLE ONLINE t1 MERGE PARTITIONS p1, p2 into PARTITION p2_new; ALTER TABLE gaussdb=# SELECT relname, boundaries, oid FROM pg_partition WHERE parentid='t1'::regclass AND parttype <> 'r' order by 1; relname | boundaries | oid ---------+------------+--------- p2_new | {10} | 4397673 p3 | {101} | 4397634 (2 rows)
- 在线切割分区。
gaussdb=# ALTER TABLE ONLINE t1 SPLIT PARTITION p2_new AT (5) INTO (PARTITION P1, PARTITION P2); ALTER TABLE gaussdb=# SELECT relname, boundaries, oid FROM pg_partition WHERE parentid='t1'::regclass AND parttype <> 'r' order by 1; relname | boundaries | oid ---------+------------+--------- p1 | {5} | 4397706 p2 | {10} | 4397707 p3 | {101} | 4397634 (3 rows)
- 在线交换分区。
gaussdb=# ALTER TABLE ONLINE t1 EXCHANGE PARTITION (p3) WITH TABLE t1_exchange; ALTER TABLE gaussdb=# SELECT COUNT(*) FROM t1 PARTITION (p3); count ------- 41 (1 row)
- 在线移动分区表空间。
gaussdb=# CREATE TABLESPACE tbs RELATIVE LOCATION 'tablespace1/tbs'; CREATE TABLESPACE gaussdb=# ALTER TABLE ONLINE t1 MOVE PARTITION p1 TABLESPACE tbs; ALTER TABLE gaussdb=# SELECT relname, spcname FROM pg_partition t1, pg_tablespace t2 WHERE T1.reltablespace=t2.oid and t1.parentid='t1'::regclass; relname | spcname ---------+--------- p1 | tbs (1 row)
- 以上在线DDL操作中,可进行并发读写操作。
gaussdb=# INSERT INTO t1 VALUES(11, 11); INSERT 0 1 gaussdb=# INSERT INTO t1_exchange VALUES(51, 51); INSERT 0 1
- 在线合并分区。
- 查看表定义。
gaussdb=# \d+ t1 Table "public.t1" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | Partition By RANGE(c2) Number of partitions: 3 (View pg_partition to check each partition range.) Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off gaussdb=# \d+ t1_exchange Table "public.t1_exchange" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off gaussdb=# SELECT relname, reltablespace, boundaries FROM pg_partition; relname | reltablespace | boundaries ---------+---------------+------------ t1 | 0 | p1 | 4397520 | {5} p2 | 0 | {10} p3 | 0 | {101} (4 rows)
- 使用VACUUM FULL在线回收分区空间。
gaussdb=# VACUUM FULL t1 PARTITION (p1) ONLINE; VACUUM
在线VACUUM FULL进度监控与调参
在线DDL系统函数请参见《参考》中“SQL参考 > 函数和操作符 > 其他系统函数”章节。
- 创建表并导入数据。
gaussdb=# CREATE TABLE t1(c1 INT,c2 INT); -- 插入一百万条数据 gaussdb=# \copy t1 FROM 'test_data_1M.tsv' parallel 32; -- 查看表格 gaussdb=# \d+ t1 Table "public.t1" Column | Type | Modifiers | Storage | Stats target | Description --------+------------------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | c3 | double precision | | plain | | Has OIDs: no Distribute By: HASH(c1) Location Nodes: ALL DATANODES Options: orientation=row, storage_type=ustore, compression=no, segment=off - 执行在线VACUUM FULL,可以在WITH后设置本次DDL参数。
gaussdb=# VACUUM FULL t1 ONLINE WITH (enable_cancel=true, parallel_threads=2); -- 等待在线Vacuum Full执行完成
- 新建会话,在线VACUUM FULL执行期间调用进度监控函数查看进度。
-- 改变gsql展示数据的样式 gaussdb=# \x Expanded display is on. gaussdb=# select * from gs_stat_progress_online_ddl(); -[ RECORD 1 ]------+--------------------------------------------------------------------- pid | 139717555775232 node_name | coordinator2 phase_id | 1 rel_schema | public rel_name | t1 sql_command | VACUUM FULL t1 online with (enable_cancel=true, parallel_threads=2); started_time | 2026-07-14 17:09:54.977 elapsed_time | 10269 phase_name | Initialization phase_started_time | 2026-07-14 17:09:54.977 phase_elapsed_time | 716 lock_level | 8 lock_try_times | 1 lock_hold_time | 705 phase_detail | -[ RECORD 2 ]------+--------------------------------------------------------------------- pid | 139717555775232 node_name | coordinator2 phase_id | 2 rel_schema | public rel_name | t1 sql_command | VACUUM FULL t1 online with (enable_cancel=true, parallel_threads=2); started_time | 2026-07-14 17:09:54.977 elapsed_time | 10269 phase_name | Base data copy phase_started_time | 2026-07-14 17:09:56.003 phase_elapsed_time | 2422 lock_level | 4 lock_try_times | 1 lock_hold_time | 2479 phase_detail | { | "total_pages": 4356, | "inserted_rows": 1000000, | "insert_speed": 447828.03403493058, | "parallel_threads": 2 | } -[ RECORD 3 ]------+--------------------------------------------------------------------- pid | 139717555775232 node_name | coordinator2 phase_id | 3 rel_schema | public rel_name | t1 sql_command | VACUUM FULL t1 online with (enable_cancel=true, parallel_threads=2); started_time | 2026-07-14 17:09:54.977 elapsed_time | 10269 phase_name | Reindexing phase_started_time | 2026-07-14 17:09:58.428 phase_elapsed_time | 4656 lock_level | 4 lock_try_times | 0 lock_hold_time | 4432 phase_detail | { | "total_indexes": 2, | "indexes_rebuilt": 0, | "parallel_threads": 2, | "parallel_workers": 1 | }
3是在线VACUUM FULL执行到重建索引阶段的实时进度展示示例,此时lock_try_times=0且indexes_rebuilt=0,说明索引重建刚启动,在线DDL尚未获取锁,且未完成任何索引重建。
- 新建会话,在线VACUUM FULL执行期间,调用切换窗口控制函数动态修改在线DDL参数及锁超时设置。
gaussdb=# SELECT * from gs_online_ddl_set_parameters('public', 't1', 'last_catchup_threshold', '10000', 'max_catchup_times', '30','parallel_threads', '2','online_ddl_lockwait_timeout', '10', 'lockwait_interval', '10', 'trylock_threshold', '1', 'enable_cancel', 'false'); parallel_threads | last_catchup_threshold | max_catchup_times | online_ddl_lockwait_timeout | lockwait_interval | trylock_threshold | enable_cancel ------------------+------------------------+-------------------+-----------------------------+-------------------+-------------------+--------------- 2 | 10000 | 30 | 10 | 10 | 1 | false (1 row) -- 通过 gs_online_ddl_set_parameters 设置CANCEL模式:当在线 DDL 第一次尝试获取常规锁失败时,允许在线DDL快速失败阻塞 Online DDL 强锁的业务事务。 gaussdb=# SELECT * from gs_online_ddl_set_parameters('public', 't1', 'online_ddl_lockwait_timeout', '10000', 'lockwait_interval', '5', 'trylock_threshold', '1', 'enable_cancel', 'true'); parallel_threads | last_catchup_threshold | max_catchup_times | online_ddl_lockwait_timeout | lockwait_interval | trylock_threshold | enable_cancel ------------------+------------------------+-------------------+-----------------------------+-------------------+-------------------+--------------- 1 | 5000 | 50 | 10000 | 5 | 1 | true (1 row)
调用gs_online_ddl_set_parameters后,函数将输出目标表上经过本次调用更新完成后的在线DDL参数。若目标表无正在执行的在线DDL与在线VACUUM FULL操作,函数返回空行。