更新时间:2026-10-21 GMT+08:00
分享

在线DDL

在线DDL支持对正常业务影响较小的情况下进行DDL,减少对业务的影响,提高业务运行的连续性和数据库的可用性。部分在线DDL只需要修改元数据,不涉及重建数据,操作时长较快,对业务影响较小。传统DDL操作若涉及重建数据,例如修改列类型、移动表空间、VACUUM FULL等操作,会对操作的表加长时间的排他锁,阻塞对该表的并发读写操作,影响用户业务运行。阻塞时长与数据量成正比,当数据量较大时,阻塞时长可达数小时、甚至数天。相比之下,在线DDL不会长时间加排他锁,执行中允许对该表的并发读写操作,减少对用户业务运行影响。

  • 使用DDL功能时,数据库需正常运行。

使用在线DDL操作过程中进行并发读写操作

  1. 创建表。

    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

  2. 历史版本已支持的在线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

  3. 设置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

  4. 查看表结构。

    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

  5. 使用VACUUM FULL在线回收表空间。

    gaussdb=# VACUUM FULL t1 ONLINE;
    VACUUM

使用分区在线DDL操作过程中进行并发读写操作

  1. 创建分区表和普通表。

    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

  2. 设置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

  3. 查看表定义。

    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)

  4. 使用VACUUM FULL在线回收分区空间。

    gaussdb=# VACUUM FULL t1 PARTITION (p1) ONLINE;
    VACUUM

在线VACUUM FULL进度监控与调参

在线DDL系统函数请参见《参考》中“SQL参考 > 函数和操作符 > 其他系统函数”章节。

  1. 创建表并导入数据。

    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

  2. 执行在线VACUUM FULL,可以在WITH后设置本次DDL参数。

    gaussdb=# VACUUM FULL t1 ONLINE WITH (enable_cancel=true, parallel_threads=2);
    
    -- 等待在线Vacuum Full执行完成

  3. 新建会话,在线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尚未获取锁,且未完成任何索引重建。

  4. 新建会话,在线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操作,函数返回空行。

相关文档