MogDB/openGauss的三種函式穩定性關鍵字

T1YSL發表於2023-11-07

一、ORACLE中的類似的函式穩定性關鍵字(DETERMINISTIC)

在ORACLE裡,function有著一個DETERMINISTIC引數,它表示一個函式在輸入不變的情況下輸出是否確定,只要輸入的引數一樣,返回的結果一定一樣的,以保證函式對於任何輸入總是完全相同的方式處理引數,oracle的內建函式 UPPER,TRUNC 等都是 deterministic 函式。具體例子如下:

----帶DETERMINISTIC的現象
create or replace function f_t(i_p int) return number DETERMINISTIC is
      i_rtn number;
    begin
      i_rtn := i_p * dbms_random.value(1,10);
      return i_rtn;
    end;
    /
select LEVEL,f_t(1) FROM DUAL CONNECT BY LEVEL<=10;
----不帶DETERMINISTIC的現象
 create or replace function f_t(i_p int) return number is
       i_rtn number;
    begin
       i_rtn := i_p * dbms_random.value(1,10);
       return i_rtn;
    end;
    /
select LEVEL,f_t(1) FROM DUAL CONNECT BY LEVEL<=10;

image.png

可以看到,帶了DETERMINISTIC引數的,多次執行的結果都是一樣的,能保證函式的穩定性。

二、MogDB/openGauss的三種函式穩定性狀態

而MogDB資料庫的函式雖然沒有DETERMINISTIC關鍵字,但是函式也有著類似的三種狀態的關鍵字,分別是immutable、stable和volatile。合理使用著三種不同的狀態可以顯著改善函式效能。
在資料庫裡使用\d create function也可以看到這三種狀態的關鍵字提示。

image.png

IMMUTABLE(非常穩定)

任何時候呼叫,只要函式的引數不變結果就不變。 純函式,執行結果可能會在規劃時被預求值並快取。
允許最佳化器在一個查詢用常量引數呼叫該函式時提前計算該函式, 整數加法運算子底層的函式被 標記為IMMUTABLE。

表示該函式不能修改資料庫並且對於給定的引數值總是會返回相同的值。 也就是說,它不會做資料庫查詢或者使用沒有在其引數列表中直接出現的資訊。immutable, 和stable非常類似, 但是immutable是指在任何情況下, 只要引數一致, 結果就一致。

STABLE(穩定)

穩定,在一個事務中呼叫時,只要函式的引數不變結果就不變。
STABLE函式不能修改資料庫狀態,但是對於相同的引數值,它在一次表掃描中將返回相同的結果。
因而最佳化器可以將相同引數的多次呼叫最佳化成一次呼叫。 在索引掃描條件中允許使用STABLE函式。

在大多數情況下是的。在單個表掃描中,對相同的引數值返回相同的結果,但結果將透過SQL語句進行更改。 結果取決於資料庫查詢或引數值。 current_timestamp系列函式是 STABLE; 值在執行中不會改變。

immutable和stable很像, 顯著的區別是最佳化器對immutable和stable函式的處理上,immutable函式在最佳化器生成執行計劃時會將函式結果替換函式. 也就是函式不在輸出的執行計劃中, 取而代之的是一個結果常量。stable函式則不會如此, 執行計劃輸出後還是函式。

immutable和stable在呼叫次數上的明顯區別可以用如下的測試驗證出來:

CREATE OR REPLACE FUNCTION func_out_num() RETURNS INTEGER AS
$$
BEGIN
RAISE NOTICE 'Invoke the func.';
RETURN 6;
END;
$$ LANGUAGE PLPGSQL STABLE;
select func_out_num() from generate_series(1,10);
alter function func_out_num() immutable;
select func_out_num() from generate_series(1,10);

image.png

在本例中,當使用STABLE關鍵字的時候,會按照呼叫10次函式,而當使用IMMUTABLE關鍵字時,它會被最佳化為一次呼叫。

除此之外, 把函式內容放到結果集部分,兩種狀態的差異也很大,如下測試可以看出:

MogDB=# create table test_stable (id int, info text);  
CREATE TABLE
MogDB=# insert into test_stable select generate_series(1,100000),random()::text;  
INSERT 0 1000
MogDB=# create index idx_test_a on test(id);  
CREATE INDEX

建立如下函式

create or replace function func_stable() returns numeric as $$  
declare  
begin  
  return 2;  
end;  
$$ language plpgsql stable;

image.png

使用如下語句可以進行驗證兩種方式的執行計劃時間明顯不同。

explain analyze select func_stable() from test_stable;

image.png
因此,在事務中引數一致則結果一致,且只關注函式的最終結果可以標記為immutable,因為它呼叫函式的次數少,固化了函式的結果,執行計劃的代價較小。但是一般還是建議使用stable,因為它會老老實實的去執行函式,而不是隻取一個固化的結果。

VOLATILE(不穩定)

預設為VOLATILE。表示該函式的值在一次表掃描中都有可能改變,因此不能做最佳化。

VOLATILE函式可以做任何事情,包括修改資料庫狀態。 在連續呼叫時即使使用相同的引數,也可能會返回不同的結果。 最佳化器不會最佳化掉此類函式,每次呼叫都會重新求值。
在這種意義上,相對較少的資料庫函式是不穩定的。 例如: random(), currval(), timeofday()。 任何具有副作用的函式的都不穩定的,即使其結果是可預測的。例如: setval()。

只有函式宣告瞭VOLATILE狀態才可以進行update操作。

具體的驗證如下所示:

MogDB=# create table test_volatile (id int, info text);  
CREATE TABLE
MogDB=# insert into test_volatile select generate_series(1,1000),random()::text;  
INSERT 0 1000
MogDB=# create index idx_test on test(id);  
CREATE INDEX

然後建立測試的函式

create or replace function func_volatile(ida int) returns text as $$  
declare  
  result text;  
begin   
  update test_volatile set info='xiaoguaishou' where id=ida returning info into result;  
  return result;  
end;
$$ language plpgsql volatile;

可以看到測試結果:

image.png


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69990629/viewspace-2993185/,如需轉載,請註明出處,否則將追究法律責任。

相關文章