你的數倉函數結果不穩定,可能是屬性指定錯了


摘要:本文簡單介紹GaussDB(DWS)函數下推屬性的相關知識,並提供幾個函數屬性相關的典型案例供大家參考。

用戶在使用GaussDB(DWS)時,應該正確指定函數屬性,錯誤指定函數屬性不僅會導致查詢語句執行效率低,而且可能會導致結果集不穩定的情況。本文簡單介紹GaussDB(DWS)函數下推屬性的相關知識,並提供幾個函數屬性相關的典型案例供大家參考。

1. 函數下推屬性介紹

GaussDB(DWS)創建函數時,可以指定許多函數屬性,其中,與函數下推相關的屬性為易失性級別 下推屬性,其中:

易失性:

  • 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,使用該函數時執行計划如下:

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;

調用該函數發現以下現象:

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表后函數返回預期發生變化,優化方法:

(1)將函數改為不下推:alter function get_count() not shippable;

(2)將函數中用到的表改為復制表,這樣每個DN上都是一份該表的全量數據,即使下推到DN執行,也能保證結果集符合預期。

3. 總結

創建自定義函數時,要正確指定函數的屬性,確保函數屬性符合預期,防止因函數屬性設置不正確導致的性能下降或結果集不穩定。

 本文分享自華為雲社區《GaussDB(DWS)函數下推屬性介紹》,原文作者:Arrow0lf。

點擊關注,第一時間了解華為雲新鮮技術~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM