更新时间: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的组合场景。
- 不支持更新视图。
- 伪更新分布列可消除的场景,支持消除后不更新分布列场景,可不遵循说明中罗列的不支持场景。
-
/*+ 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;
父主题: UPDATE