PostgreSQL 9.4内核的GreenPlum为了执行upsert操作,写了一个触发器在table上,但是执行时报错
SQL:错误
ERROR: function cannot execute on a QE slice because it accesses relation "public.etk_lg_life" (seg0 172.29.145.141:33000 pid=18126)
CONTEXT: SQL statement "SELECT not exists
(select 1 from etk_lg_life t1 where t1.fbh=NEW.fbh limit 1)"
PL/pgSQL function upsert_imp() line 4 at IF
百度搜到一个解释:
UDF(User Defined Function)用户自定义函数在 segment 上不能访问任何表。由于 MPP 的特性,任何 segment 仅仅包含部分数据,因而在 segment 执行的 UDF 不能访问任何表,否则数据计算错误。Greenplum 支持另一种分布策略:复制表,即整张表在每个节点上都有一个完整的拷贝。可使用以下命令进行设置:
ALTER TABLE table_name SET DISTRIBUTED REPLICATED;
数据量大的表不适合使用复制表模式,一些不经常变动的数据量比较小的比如码表可以使用DISTRIBUTED REPLICATED模式,查询性能也会有明显的提升。
最后,亲测可用
补充1:
另外搜到一个解决方案,但是我没尝试
在一次存储过程开发时遇到如上问题,出现该问题的原因是:在存储过程中调用了自定义函数,而自定义函数涉及到表查询,问题关键在于这张表的分布键是随机分布导致跨sql出现QE错误。问题解释可以参考如下:
如果不能确定一张表的哈希分布键或者不存在合理的避免数据倾斜的分布键,则可以使用随机分布。随机分布会采用循环的方式将一次插入的数据存储到不同的节点上。随机性只在单个 SQL 中有效,不考虑跨 SQL 的情况。譬如如果每次插入一行数据到随机分布表中,最终的数据会全部保存在第一个节点上。
解决办法:
把自定义函数使用到的表再创建一个字段相同的负值表,即
CREATE TABLE a_copy( x1 varchar --你的字段名 ); DISTRIBUTED REPLICATED; --把分布键语句改为这一句;
在函数中使用复制表就不会再出现以上错误。