1. 程式人生 > 其它 >KINGBASE函式穩定性與執行效率

KINGBASE函式穩定性與執行效率

一、函式的屬性

PostgreSQL中的函式在定義時有三種穩定性級別:volatile、stable 和 immutable。預設情況下,建立函式的穩定性為volatile。以下是這三種函式的區別:

  • Volatile 函式可以做任何事情,包括修改資料庫。在呼叫中,輸入同樣的引數會返回不同的結果。在一個Query中,對於每一行都會重新計算該函式。
  • Stable 函式不能修改資料庫,單個Query中所有行給定同樣的引數確保返回相同的結果。這種穩定級別允許優化器將多次函式呼叫轉換為一次。在索引掃描的條件中使用這種函式是可行的,因為索引掃描只計算一次比較值(comparison value),而不是每行都計算一次。
  • Immutable 函式不能修改資料庫,在任何情況下,只要輸入引數相同,返回結果就相同。這種級別的函式,優化器可以提前進行計算,在查詢過程中作為常量引數。比如:SELECT...WHERE x=2+2 可以簡化為SELECT...WHERE x=4。
  • deterministic 這是KINGBASE 為了與oracle 相容而增加的一個屬性,效果與 immutable 相同。

穩定性級別使得優化器可以判斷不同函式的行為。為了得到最佳的優化結果,在建立函式時我們應該指定嚴格的穩定性級別。

二、不同屬性對於效能的影響

以下舉例說明函式的屬性影響相同引數情況多次執行的效率。

1、構建函式和資料

create table t1(id integer); 並插入100條完全相同的資料。

create or replace function test_volatile(i integer) returns varchar volatile
as 
begin
  perform pg_sleep(1);
  return 'a';
end;
/

create or replace function test_stable(i integer) returns varchar stable
as 
begin
  perform pg_sleep(1);
  return 'a';
end;
/

create or replace function test_immutable(i integer) returns varchar immutable
as 
begin
  perform pg_sleep(1);
  return 'a';
end;
/

2、以列為引數呼叫函式

可以看到三個函式呼叫時間基本沒有差別,因為,傳入的引數是id 變數值(雖然實際值是相同的)。

test=# select count(*) from t1 where test_volatile(id)='a';
 count 
-------
   100
(1 row)
Time: 100119.793 ms (01:40.120)

test=# select count(*) from t1 where test_stable(id)='a';   
 count 
-------
   100
(1 row)
Time: 100128.597 ms (01:40.129)

test=# select count(*) from t1 where test_immutable(id)='a';
 count 
-------
   100
(1 row)
Time: 100124.366 ms (01:40.124)

3、傳入常量值

可以看到,對於常量值,stable 和 immutable 型別的函式實際只需呼叫一次。

test=# select count(*) from t1 where test_volatile(1)='a';
count 
-------
   100
(1 row)
Time: 100119.814 ms (01:40.120)

test=# select count(*) from t1 where test_stable(1)='a';
 count 
-------
   100
(1 row)
Time: 1001.344 ms (00:01.001)

test=# select count(*) from t1 where test_immutable(1)='a';
 count 
-------
   100
(1 row)

Time: 1001.393 ms (00:01.001)

對於for 迴圈,實際結果相同。

test=# begin
test-#   for i in 1..100 loop
test-#     perform test_immutable(1);
test-#   end loop;
test-# end;
test-# /
ANONYMOUS BLOCK
Time: 1001.184 ms (00:01.001)

三、最後來看oracle表演

SQL> create table t1(id integer);

Table created.

SQL> insert into t1 select 1 from dba_objects where rownum<101;

100 rows created.

SQL> create or replace function test_immutable(i integer) return varchar deterministic
  2  as 
  3  begin
  4    dbms_lock.sleep(1);
  5    return 'a';
  6  end;
  7  /

Function created.

SQL> 
SQL> 
SQL> create or replace function test_volatile(i integer) return varchar
  2  as 
  3  begin
  4    dbms_lock.sleep(1);
  5    return 'a';
  6  end;
  7  /

Function created.

SQL> select count(*) from t1 where test_immutable(id)='a'; 

  COUNT(*)
----------
       100

Elapsed: 00:00:01.02SQL> select count(*) from t1 where test_volatile(id)='a'; 

  COUNT(*)
----------
       100

Elapsed: 00:01:40.01

可以看到即使傳入的是 id 列,oracle 也能很好的避免函式的重複呼叫。