你的数仓函数结果不稳定,多是属性指定错了

摘要:本文简单介绍GaussDB(DWS)函数下推属性的相关知识,并提供几个函数属性相关的典型案例供你们参考。

用户在使用GaussDB(DWS)时,应该正确指定函数属性,错误指定函数属性不只会致使查询语句执行效率低,并且可能会致使结果集不稳定的状况。本文简单介绍GaussDB(DWS)函数下推属性的相关知识,并提供几个函数属性相关的典型案例供你们参考。node

1. 函数下推属性介绍

GaussDB(DWS)建立函数时,能够指定许多函数属性,其中,与函数下推相关的属性为易失性级别 下推属性,其中:sql

易失性:

  • IMMUTABLE:该属性的函数不会修改数据库,而且保证在任何状况下一样的输入参数永远返回一样的结果;
  • STABLE:该属性的函数不会修改数据库,而且保证在同一个查询中,对于一样的输入参数,函数返回的结果相同;
  • VOLATILE:该属性的函数对于一样的输入参数,函数的返回结果可能不通,典型的如timeofday,建立函数时若是未明确指定,则默认为VOLATILE;

下推属性:

  • SHIPPABLE:函数能够下推到DN执行
  • NOT SHIPPABLE:函数不能下推到DN执行,建立函数时若是未明确指定,则默认为NOT SHIPPABLE。

在GaussDB(DWS)中,IMMUTABLE属性的函数时必定可以下推到DN执行的,无论下推属性是否为SHIPPABLE,对于STABLE和VOLATILE属性的函数,函数是否能下推要看指定的SHIPPABLE属性。所以,在建立函数时若是同时指定了IMMUTABLE 和 NOT SHIPPABLE的属性,函数建立成功时会有如下提示:数据库

NOTICE:  Immutable function will be shippable anyway.

2. 函数下推属性典型案例

案例一:未指定函数易失性级别致使函数不下推

函数定义以下:函数

create function try_cast_int(p_in text, p_default int default 0) returns int
as $$
begin
    begin
        return $1::int;
    exception
    when others then
        return p_default;
    end;
end;
$$
language plpgsql;

因为建立函数时未明确指定函数易失性级别和函数属性,函数默认为VOLATILE NOT SHIPPABLE,使用该函数时执行计划以下:post

postgres=# explain verbose select try_cast_int(b) from test order by a;
                                      QUERY PLAN                                      
--------------------------------------------------------------------------------------
 Sort  (cost=13.91..14.04 rows=50 width=36)
   Output: (try_cast_int(test.b, 0)), test.a
   Sort Key: test.a
   ->  Data Node Scan on "__REMOTE_SORT_QUERY__"  (cost=0.00..12.50 rows=50 width=36)
         Output: try_cast_int(test.b, 0), test.a
         Node/s: All datanodes
         Remote query: SELECT a, b FROM ONLY public.test WHERE true ORDER BY 1
(7 rows)

能够看出该sql执行计划不下推,执行效率较低,分析该函数发现该函数能够指定为IMMUTABLE属性,让该函数能够下推,所以,能够经过如下方式优化:性能

ALTER FUNCTION try_cast_int(text,int) IMMUTABLE;

案例二:错误指定了函数下推属性致使结果集不稳定

下推函数可以下推到DN执行,与不下推函数相比有着更高的执行效率,有时开发者为了加快函数执行效率,全部自定义函数建立时都会指定为SHIPPABLE,某函数定义以下:优化

create function get_count() returns int
SHIPPABLE
as $$
declare
    result int;
begin
    result = (select count(*) from test);  --test表是hash表
    return result;
end;
$$
language plpgsql;

调用该函数发现如下现象:spa

postgres=# select get_count();
 get_count 
-----------
      2106
(1 row)

postgres=# select get_count() from t_src;
 get_count 
-----------
      1032
(1 row)

发现加上from表以后函数的返回值结果发生了变化!为何会出现这种状况呢?这是由于因为这个函数指定了SHIPPABLE的函数属性,所以生成计划时该函数会下推到DN上执行,该函数下推到DN后,因为函数定义中的test表是hash表,所以每一个DN上只有该表的一部分数据,因此select count(*) from test返回的结果不是test表全量数据的结果,而是每一个DN上部分数据的结果,所以致使加上from表后函数返回预期发生变化,优化方法:code

(1)将函数改成不下推:alter function get_count() not shippable;blog

(2)将函数中用到的表改成复制表,这样每一个DN上都是一份该表的全量数据,即便下推到DN执行,也能保证结果集符合预期。

3. 总结

建立自定义函数时,要正确指定函数的属性,确保函数属性符合预期,防止因函数属性设置不正确致使的性能降低或结果集不稳定。

 本文分享自华为云社区《GaussDB(DWS)函数下推属性介绍》,原文做者:Arrow0lf。

点击关注,第一时间了解华为云新鲜技术~

相关文章
相关标签/搜索