1. 程式人生 > 其它 >KINGBASE 支援全域性臨時表

KINGBASE 支援全域性臨時表

Postgresql 支援會話級別的臨時表,表的存續期只在建立臨時表的會話存活期間,會話退出後,臨時表自動刪除,表結構及資料也無法跨會話共享。KINGBASE除了支援PG原生的臨時表機制外,還支援類似oracle 的臨時表機制,也就是全域性臨時表。全域性臨時表支援表結構共享,避免使用者每次了都需要建立臨時表的操作。以下以例子的形式,介紹PG 臨時表與全域性臨時表的機制與差異。

一、PG 支援的臨時表

會話A:建立臨時表

test=# create temporary table temp_t1(id integer);
CREATE TABLE
test=# insert into temp_t1 values(1
); INSERT 0 1 test=# \d List of relations Schema | Name | Type | Owner -----------+---------------------+-------+-------- pg_temp_4 | temp_t1 | table | system test=# select * from temp_t1; id ---- 1

會話B:

test=# select * from pg_temp_4.temp_t1;
ERROR:  cannot access temporary tables of other sessions

PG 臨時表機制總結:

  • 建立語法上,臨時表可以選擇global or local,但實際都是local的(PG 後續語法不再支援 global),其它會話不能訪問(實際是空表可以訪問,有資料情況下就會報錯)。
  • ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP }
    • PRESERVE ROWS 表示臨時表的資料在事務結束後保留。預設使用的是PRESERVE ROWS。
    • DELETE ROWS 表示臨時表的資料在事務結束後truncate掉。
    • DROP 表示臨時表在事務結束後刪除。
  • 當會話第一次建立臨時表時,會自動建立 SYS_TEMP_XXX 模式,該會話的所有臨時表都放在該模式下。如果表裡有可能產生toast儲存的欄位,也會同時建立pg_toast_temp_XXX模式。
  • 臨時表在會話結束後會自動刪除(或者在事務結束後刪除on commit drop),也就是說每個會話需要使用臨時表的話需要重新建立。
  • 如果有臨時表和非臨時表重名了, 那麼預設是使用臨時表的,因為臨時表模式在search_path 引數值裡是排在最前面的。如果要使用非臨時表,需要帶上schema,如schema.table。
  • 臨時表上建立的索引也是臨時的。
  • 臨時表的統計資訊不會被autovacuum daemon自動收集,所以如果有複雜查詢的話,最好在有DML後執行analyze。

二、全域性臨時表

PG 建臨時表時也可以用 create global temporary table,但實際建立的都是local 級別的。KINGBASE 如果用create global temporary table,實際意義上建立的是全域性的臨時表,臨時表的機制與oracle相似。

A會話:建立臨時表

test=# create global temporary table g_temp_t1(id integer) on commit preserve rows;
CREATE TABLE
test=# insert into g_temp_t1 values(1);
INSERT 0 1
test=# select * from g_temp_t1;
 id 
----
  1
(1 row)

test=# \d 
                List of relations
  Schema   |        Name         | Type  | Owner  
-----------+---------------------+-------+--------
 pg_temp_4 | temp_t1             | table | system
 public    | g_temp_t1           | table | system

B會話:可以訪問A會話建立的臨時表

test=# select * from g_temp_t1;
 id 
----
(0 rows)

test=# insert into g_temp_t1 values(2);
INSERT 0 1
test=# select * from g_temp_t1;        
 id 
----
  2

A會話:會話退出後,表結構還在,但A會話插入的資料沒有了。

test=# select * from g_temp_t1;
 id 
----
  1
(1 row)

test=# \q
[kingbase@dbhost03 ~]$ ksql -d test -U system
ksql (V8.0)
Type "help" for help.

test=# \d
               List of relations
 Schema |        Name         | Type  | Owner  
--------+---------------------+-------+--------
 public | g_temp_t1           | table | system
 public | sys_stat_statements | view  | system
 
test=# select * from g_temp_t1;
 id 
----
(0 rows)

KINGBASE 全域性臨時表總結:

  • 與oracle一樣,預設是 on commit delete rows
  • 臨時表資料只對當前會話或事務可見。每個會話只能檢視和修改自己的資料。

三、普通表、臨時表、全域性臨時表字典資訊差異

test=# select relnamespace::regnamespace, relname,relpersistence,relkind,reltablespace from pg_class where relname in ('t1','temp_t1','g_temp_t1');
 relnamespace |  relname  | relpersistence | relkind | reltablespace 
--------------+-----------+----------------+---------+---------------
 public       | t1        | p              | r       |             0
 public       | g_temp_t1 | s              | r       |             0
 pg_temp_5    | temp_t1   | t              | r       |             0

以下幾點需要注意:

  • relkind 都為 r ,都是relation。
  • relpersistence 不同,全域性臨時表為 s ,普通臨時表為 t
  • relnamespace 不同,普通臨時表是建立在 pg_temp_xxx 模式下
  • 不管是全域性臨時表,還是普通臨時表,預設都是unlogged 方式

四、效能比較

test=# create table t1(id integer,name varchar(200));
CREATE TABLE
test=# create temporary table temp_t1(id integer,name varchar(200));
CREATE TABLE
test=# create global temporary table g_temp_t1(id integer,name varchar(200));
CREATE TABLE

BEGIN
for i in 1..200000 loop
  insert into g_temp_t1 values(i,repeat('a',200));
end loop;
END;
/
ANONYMOUS BLOCK
Time: 1684.636 ms (00:01.685)

BEGIN
for i in 1..200000 loop
  insert into temp_t1 values(i,repeat('a',200));
end loop;
END;
/
ANONYMOUS BLOCK
Time: 741.746 ms


BEGIN
for i in 1..200000 loop
  insert into t1 values(i,repeat('a',200));
end loop;
END;
/
ANONYMOUS BLOCK
Time: 944.549 ms

test=# insert into temp_t1 select generate_series(1,500000),repeat('a',200);
INSERT 0 500000
Time: 484.780 ms

test=# insert into g_temp_t1 select generate_series(1,500000),repeat('a',200); INSERT 0 500000 Time: 2606.722 ms (00:02.607)
test
=# insert into t1 select generate_series(1,500000),repeat('a',200); INSERT 0 500000 Time: 1856.685 ms (00:01.857)

通過觀察日誌,可以看到本地臨時表、全域性臨時表基本不產生redo日誌。但從實際執行效率看,全域性臨時表的效率是最差的,甚至不如普通的表。但這不妨礙全域性臨時表的使用,不產生Redo就是最好的優點。

五、全域性臨時表實現機制

根據全域性臨時表的relfilenode,我們查找了相關的表,發現數據庫目錄下有如下檔案:

-rw------- 1 kingbase kingbase     8192 Jun 16 15:45 t5_19820
-rw------- 1 kingbase kingbase     8192 Jun 16 15:47 t4_19820

每個檔案實際對應一個事務,事務提交後,對應檔案也就刪除。