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

伪更新分布列

功能描述

执行UPDATE语句更新分布列时,GaussDB会检查等值的分布列,并通过查询重写机制消除未实际参与更新的分布列信息,从而避免未实际更新的分布列删除或重建操作导致的SELECT FOR UPDATE语法可见性报错。该功能由GUC参数enable_remove_redundant_update_col控制,参数取值为on时开启该功能。

该功能开启后实际效果如下所示:

原始用户语句:

UPDATE TABLE SET distkey=value,amount=10000 WHERE distkey=value;

查询重写后语句:

UPDATE TABLE SET amount=10000 WHERE distkey=value;

该功能开启前,伪更新分布列会有如下报错(不会有额外报错信息提示):

ERROR:  Distributed key cannot be updated in the current version.

约束

  • 仅支持ORA兼容性。
  • 仅支持HASH分布的表。
  • 伪更新分布列语法约束:
    • 仅支持UPDATE语法,不支持MERGE INTO、REPLACE INTO、UPSERT语法。
    • 仅支持在查询重写阶段能计算出实际值的场景。包含以下场景:
      • 普通const常量:数字、字符串等值传递数据。
      • 参数类型:PBE报文中的常量值传递(数字、字符串等)。
      • 函数类型:immutable函数(stable、volatile函数不支持)。
      • 操作符类型:入参为常量的一般操作符(+-*/等)。
      • 支持部分bool表达式类型:or、and、not传参为常量的场景。
      • 显式类型转换:常量显式类型转换场景('1.23'::numeric)。
      • 条件表达式类型:case when参数为常量场景。nvl/coalesce参数为常量场景。
      • NULL类型:NULL值场景。
    • 仅支持等值表达式,不支持大于、小于、between、in等区间范围。
    • 不支持子查询场景。
    • 不支持UPDATE和CTE的组合场景。
    • 不支持更新视图。
  • 伪更新分布列可消除的场景,支持消除后不更新分布列场景,可不遵循说明中罗列的不支持场景。
  • 伪更新分布列会强行选择cplan,计划选择的优先级如下:

    /*+ use_gplan*/ > 伪更新分布列 > plan_cache_mode。

示例

  • 示例1:nvarchar2类型支持伪更新分布列
    -- 创建测试用数据库。
    gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA';
    gaussdb=# \c ora_db
    
    -- 创建hash分布表。
    ora_db=# CREATE TABLE test_hash(
        id       nvarchar2(10),
        name     VARCHAR(20),
        province VARCHAR(60),                       --省
        country   VARCHAR(30) DEFAULT 'Country1'        --国籍
    )DISTRIBUTE BY HASH(id);
    ora_db=# INSERT INTO test_hash VALUES ('0000001', 'Bob',   'City1', 'Country1'),
        ('0000002', 'Jack',  'City2',  'Country1'),
        ('0000003', 'Scott', 'City2',  'Country1');
    
    -- 原场景报错。
    ora_db=# UPDATE test_hash SET id = '0000001', name = 'bob1' WHERE id = '0000001';
    ERROR:  Distributed key cannot be updated in the current version.
    
    -- 开启功能后不报错。
    ora_db=# SET enable_remove_redundant_update_col=on;
    ora_db=# UPDATE test_hash SET id = '0000001', name = 'bob1' WHERE id = '0000001';
    UPDATE 1
    
    -- 计划展示(set中投影列id = '0000001',被成功消减)。
    ora_db=# EXPLAIN VERBOSE UPDATE test_hash SET id = '0000001', name = 'bob1' WHERE id = '0000001';
                                                      QUERY PLAN
    ---------------------------------------------------------------------------------------------------------------
     Data Node Scan on "__REMOTE_FQS_QUERY__"  (cost=0.00..0.00 rows=0 width=0)
       Node/s: datanode1
       Remote query: UPDATE public.test_hash SET name = 'bob1'::character varying WHERE id::text = '0000001'::text
    (3 rows)
    
    -- 删除测试用数据库,请用实际初始数据库名替换postgres。
    ora_db=# \c postgres
    gaussdb=# DROP DATABASE ora_db;
  • 示例2:多分布键支持伪更新分布列
    -- 创建测试用数据库。
    gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA';
    gaussdb=# \c ora_db
    
    -- 开启功能。
    ora_db=# SET enable_remove_redundant_update_col=on;
    
    -- 创建hash分布表。
    ora_db=# CREATE TABLE test_hash_multi_distcol(
        id       int,
        name     VARCHAR(20),
        province VARCHAR(60),                       --省
        country   VARCHAR(30) DEFAULT 'Country1'        --国籍
    )DISTRIBUTE BY HASH(id,name);
    ora_db=# INSERT INTO test_hash_multi_distcol VALUES (1, 'Bob',   'City1', 'Country1'),
        (2, 'Jack',  'City1',  'Country1'),
        (3, 'Scott', 'City2',  'Country1');
    
    -- 开启功能后不报错。
    ora_db=# UPDATE test_hash_multi_distcol SET id = 1,name='Bob', province = 'City1' WHERE id = 1 and name='Bob';
    UPDATE 1
    
    -- 计划展示。
    ora_db=# EXPLAIN VERBOSE UPDATE test_hash_multi_distcol SET id = 1,name='Bob', province = 'City1' WHERE id = 1 AND name='Bob';
                                                                      QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------------------------------------
     Data Node Scan on "__REMOTE_FQS_QUERY__"  (cost=0.00..0.00 rows=0 width=0)
       Node/s: datanode3
       Remote query: UPDATE public.test_hash_multi_distcol SET province = 'City1'::character varying WHERE id = 1 AND name::text = 'Bob'::text
    (3 rows)
    
    -- 删除测试用数据库,请用实际初始数据库名替换postgres。
    ora_db=# \c postgres
    gaussdb=# DROP DATABASE ora_db;
  • 示例3:PBE场景支持伪更新分布列
    -- 创建测试用数据库。
    gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA';
    gaussdb=# \c ora_db
    
    -- 开启功能。
    ora_db=# SET enable_remove_redundant_update_col=on;
    
    -- 创建hash分布表。
    ora_db=# CREATE TABLE test_hash_int(
        id       int,
        name     VARCHAR(20),
        province VARCHAR(60),                       --省
        country   VARCHAR(30) DEFAULT 'Country1'        --国籍
    )DISTRIBUTE BY HASH(id);
    ora_db=# INSERT INTO test_hash_int VALUES (1, 'Bob',   'City1', 'Country1'),
        (2, 'Jack',  'City2',  'Country1'),
        (3, 'Scott', 'City2',  'Country1');
    
    ora_db=# SELECT a.count,b.node_name
        FROM (SELECT COUNT(*) AS count, xc_node_id FROM test_hash_int GROUP BY xc_node_id) a,
        pgxc_node b
    WHERE a.xc_node_id=b.node_id ORDER BY a.count DESC;
     count | node_name
    -------+-----------
         2 | datanode2
         1 | datanode1
    (2 rows)
    
    -- 开启功能后不报错。
    ora_db=# PREPARE p1 AS UPDATE test_hash_int SET id = $1, name = $2 WHERE id = $3;
    PREPARE
    ora_db=# EXECUTE p1(1,'bob1',1);
    UPDATE 1
    
    -- 删除测试用数据库,请用实际初始数据库名替换postgres。
    ora_db=# \c postgres
    gaussdb=# DROP DATABASE ora_db;
  • 示例4:timestamp和text隐式类型转换不支持
    -- 创建测试用数据库。
    gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA';
    gaussdb=# \c ora_db
    
    -- 开启功能。
    ora_db=# SET enable_remove_redundant_update_col = on;
    
    -- 创建hash分布表。
    ora_db=# CREATE TABLE distcol_update_timestamp(c1 timestamp(6),c2 int,c3 text) DISTRIBUTE BY hash(c1);
    ora_db=# INSERT INTO distcol_update_timestamp VALUES ('2026-03-05 09:25:19.411077+08',1,'gaussdb'),
        ('2026-03-05 09:25:19.411077+08',2,'gaussdb'),
        ('2026-03-05 09:25:20.411077+08',3,'gaussdb'),
        ('2026-03-05 09:25:21.411077+08',4,'gaussdb'),
        ('2026-03-05 09:25:22.411077+08',5,'gaussdb'),
        ('2026-03-06 09:25:22.411077+08',6,'gaussdb'),
        ('2026-03-07 09:25:22',7,'gaussdb');
    ora_db=# CREATE INDEX ON distcol_update_timestamp(c1);
    
    ora_db=# EXPLAIN VERBOSE UPDATE distcol_update_timestamp SET c1 = '2026-03-05 09:25:20.411077+08',c2 = -3
    WHERE c1 = '2026-03-05 09:25:20.411077+08'::varchar2;
                                                                               QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     Data Node Scan on "__REMOTE_FQS_QUERY__"  (cost=0.00..0.00 rows=0 width=0)
       Node/s: datanode2
       Remote query: UPDATE public.distcol_update_timestamp SET c2 = (-3) WHERE c1 = '2026-03-05 09:25:20.411077+08'::character varying::timestamp without time zone
    (3 rows)
    
    ora_db=# EXPLAIN VERBOSE UPDATE distcol_update_timestamp SET c1 = '2026-03-05 09:25:20.411077+08',c2 = -3
    WHERE c1 = '2026-03-05 09:25:20.411077+08';
                                                                    QUERY PLAN
    -------------------------------------------------------------------------------------------------------------------------------------------
     Data Node Scan on "__REMOTE_FQS_QUERY__"  (cost=0.00..0.00 rows=0 width=0)
       Node/s: datanode2
       Remote query: UPDATE public.distcol_update_timestamp SET c2 = (-3) WHERE c1 = '2026-03-05 09:25:20.411077'::timestamp without time zone
    (3 rows)
    
    ora_db=# EXPLAIN VERBOSE UPDATE distcol_update_timestamp SET c1 = '2026-03-05 09:25:20.411077+08',c2 = -3
    WHERE c1 = '2026-03-05 09:25:20.411077+08'::text;
    ERROR:  Distributed key cannot be updated in the current version.
    
    -- 两个隐式类型转换函数,一个是stable的一个是immutable的,可以通过provolatile列看到text隐式类型转换到timestamp为s类型,不支持。
    ora_db=# SELECT * FROM pg_proc WHERE proname IN ('varchar_timestamp','text_timestamp');
          proname      | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile |
    pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults |      prosrc       | probin | proconfig | proacl | prodefaultargpos | fencedmode
    | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext | allargtypes | allargtypesext
    -------------------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+-
    ---------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+-------------------+--------+-----------+--------+------------------+------------
    +--------------+------------+---------+-----------+--------------+--------------+----------------+---------------------+-------------+----------------
     text_timestamp    |           11 |       10 |      12 |       1 |       0 |           0 | -            | f        | f           | f         | f            | t           | f         | s           |
           1 |               0 |       1114 | 25          |                |             |             |                | text_timestamp    |        |           |        |                  | f
    |              | f          | f       |           |            0 | f            |                |                     | 25          |
     varchar_timestamp |           11 |       10 |      12 |       1 |       0 |           0 | -            | f        | f           | f         | f            | t           | f         | i           |
           1 |               0 |       1114 | 1043        |                |             |             |                | varchar_timestamp |        |           |        |                  | f
    |              | f          | f       |           |            0 | f            |                |                     | 1043        |
    (2 rows)
    
    -- 删除测试用数据库,请用实际初始数据库名替换postgres。
    ora_db=# \c postgres
    gaussdb=# DROP DATABASE ora_db;

    示例中强制转换varchar2类型的操作,受GUC参数modify_function_property_json影响:

    • 将GUC参数取值设置为空,或设置GUC参数中oid为4186的配置项中,property_name为provolatile的对象,对应的property_value从s改为i,并重启数据库,正常执行返回结果。
    • 不修改modify_function_property_json参数,会报错,符合预期,原因同强转text一样,函数易变性为stable,报错如下:
      ora_db=# EXPLAIN VERBOSE UPDATE distcol_update_timestamp SET c1 = '2026-03-05 09:25:20.411077+08',c2 = -3 WHERE c1 = '2026-03-05 09:25:20.411077+08'::varchar2;
      ERROR:  Distributed key cannot be updated in the current version.
  • 示例5:NVL等系统函数和隐式类型转换不支持
    -- 创建测试用数据库。
    gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA';
    gaussdb=# \c ora_db
    
    -- 开启功能。
    ora_db=# SET enable_remove_redundant_update_col=on;
    
    -- 创建hash分布表。
    ora_db=# CREATE TABLE distcol_update_timestamp(c1 timestamp(6),c2 int,c3 text) DISTRIBUTE BY HASH(c1);
    ora_db=# INSERT INTO distcol_update_timestamp VALUES ('2026-03-05 09:25:19.411077+08',1,'gaussdb'),
        ('2026-03-05 09:25:19.411077+08',2,'gaussdb'),
        ('2026-03-05 09:25:20.411077+08',3,'gaussdb'),
        ('2026-03-05 09:25:21.411077+08',4,'gaussdb'),
        ('2026-03-05 09:25:22.411077+08',5,'gaussdb'),
        ('2026-03-06 09:25:22.411077+08',6,'gaussdb'),
        ('2026-03-07 09:25:22',7,'gaussdb');
    ora_db=# CREATE INDEX ON distcol_update_timestamp(c1);
    
    -- 更新语句。
    ora_db=# UPDATE distcol_update_timestamp SET c1 = '2026-03-05 09:25:20.411077+08',c2 = -3 WHERE c1 = nvl('2026-03-05 09:25:20.411077+08','2026-03-05 09:25:21.411077+08');
    ERROR:  Distributed key cannot be updated in the current version.
    
    -- 删除测试用数据库,请用实际初始数据库名替换postgres。
    ora_db=# \c postgres
    gaussdb=# DROP DATABASE ora_db;
  • 示例6:bigint、int类型执行伪分布列更新set a = null,b = 1 where a = null报错不支持
    -- 创建测试用数据库。
    gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA';
    gaussdb=# \c ora_db
    
    -- 创建hash分布表。
    ora_db=# CREATE TABLE distcol_update_bigint(c1 bigint,c2 int,c3 text) DISTRIBUTE BY hash(c1);
    ora_db=# INSERT INTO distcol_update_bigint VALUES(null,9,'gaussdb');
    
    -- 设置参数,更新语句。
    ora_db=# SET enable_remove_redundant_update_col=on;
    ora_db=# SET a_format_version = '10c';
    ora_db=# SET a_format_dev_version = 's6';
    ora_db=# UPDATE distcol_update_bigint SET c1 = null,c3 = 'update4' WHERE c1 = null;
    ERROR:  Distributed key cannot be updated in the current version.
    
    -- 删除测试用数据库,请用实际初始数据库名替换postgres。
    ora_db=# \c postgres
    gaussdb=# DROP DATABASE ora_db;

相关文档