KINGBASE函式穩定性與執行效率
阿新 • • 發佈:2021-06-16
一、函式的屬性
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 也能很好的避免函式的重複呼叫。