摘要:本文簡單介紹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。
