應用程序通常使用某種形式的臨時數據存儲來處理過于復雜而無法一次性完成的流程。通常,這些臨時存儲被定義為數據庫表或 PL/SQL 表。從 Oracle 8i 開始,可以使用全局臨時表將臨時表的維護和管理委托給服務器。
一、臨時表分類
Oracle 支持兩種類型的臨時表。
- 全局臨時表:從 Oracle 8i 開始可用,也是本文的主題。
- 私有臨時表:自 Oracle 18c 起可用。
二、創建全局臨時表
全局臨時表中的數據是私有的,因此會話插入的數據只能由該會話訪問。全局臨時表中特定于會話的行可以為整個會話保留,也可以僅為當前事務保留。
ON COMMIT DELETE ROWS 子句指示應在事務結束或會話結束時刪除數據。
CREATE GLOBAL TEMPORARY TABLE my_temp_table (id NUMBER,description VARCHAR2(20)
)
ON COMMIT DELETE ROWS;-- Insert, but don't commit, then check contents of GTT.
INSERT INTO my_temp_table VALUES (1, 'ONE');SELECT COUNT(*) FROM my_temp_table;COUNT(*)
----------1SQL>-- Commit and check contents.
COMMIT;SELECT COUNT(*) FROM my_temp_table;COUNT(*)
----------0
相反,ON COMMIT PRESERVE ROWS 子句指示行應在事務結束后繼續保留。它們只會在會話結束時被刪除。
CREATE GLOBAL TEMPORARY TABLE my_temp_table (id NUMBER,description VARCHAR2(20)
)
ON COMMIT PRESERVE ROWS;-- Insert and commit, then check contents of GTT.
INSERT INTO my_temp_table VALUES (1, 'ONE');
COMMIT;SELECT COUNT(*) FROM my_temp_table;COUNT(*)
----------1SQL>-- Reconnect and check contents of GTT.
CONN test/testSELECT COUNT(*) FROM my_temp_table;COUNT(*)
----------0SQL>
三、全局臨時表和UNDO
雖然 GTT 中的數據被寫入臨時表空間,但關聯的 undo 仍然寫入普通 undo 表空間,普通 undo 表空間本身受重做保護,因此使用 GTT 并不會減少 undo 以及與保護 undo 表空間相關的重做。
以下代碼創建一個常規表,填充它并檢查事務使用的撤消量。
DROP TABLE my_temp_table PURGE;-- Create conventional table.
CREATE TABLE my_temp_table (id NUMBER,description VARCHAR2(20)
);-- Populate table.
INSERT INTO my_temp_table
WITH data AS (SELECT 1 AS idFROM dualCONNECT BY level < 10000
)
SELECT rownum, TO_CHAR(rownum)
FROM data a, data b
WHERE rownum <= 1000000;-- Check undo used by transaction.
SELECT t.used_ublk,t.used_urec
FROM v$transaction t,v$session s
WHERE s.saddr = t.ses_addr
AND s.audsid = SYS_CONTEXT('USERENV', 'SESSIONID');USED_UBLK USED_UREC
---------- ----------302 6237
現在我們重復前面的測試,但這次使用GTT。
DROP TABLE my_temp_table PURGE;-- Create GTT.
CREATE GLOBAL TEMPORARY TABLE my_temp_table (id NUMBER,description VARCHAR2(20)
)
ON COMMIT PRESERVE ROWS;-- Populate GTT.
INSERT INTO my_temp_table
WITH data AS (SELECT 1 AS idFROM dualCONNECT BY level < 10000
)
SELECT rownum, TO_CHAR(rownum)
FROM data a, data b
WHERE rownum <= 1000000;-- Check undo used by transaction.
SELECT t.used_ublk,t.used_urec
FROM v$transaction t,v$session s
WHERE s.saddr = t.ses_addr
AND s.audsid = SYS_CONTEXT('USERENV', 'SESSIONID');USED_UBLK USED_UREC
---------- ----------303 6238SQL>
對比undo塊
我們可以看到,所使用的undo沒有顯著差異。
Oracle 12c引入了臨時撤銷的概念,允許將GTT的撤銷寫入臨時表空間,從而減少了撤銷和重做。
四、全局臨時表和REDO
?GTT中的數據寫入了臨時表空間,該表空間不受重做的直接保護,因此使用GTT通過減少重做生成來改善性能。不幸的是,在Oracle 12c之前,所有與DML相關的dml與GTT相關聯的撤消均寫入正常的撤消表空間,該表本身受重做的保護。結果,使用GTT減少了重做生成的數量,但不會消除它。描述這一點的另一個原因是,使用GTT消除了直接的重做生成,而不是通過撤消的間接重做生成。
以下代碼創建一個常規表,填充它并檢查事務生成的重做量。
DROP TABLE my_temp_table PURGE;-- Create conventional table.
CREATE TABLE my_temp_table (id NUMBER,description VARCHAR2(20)
);SET AUTOTRACE ON STATISTICS;-- Populate table.
INSERT INTO my_temp_table
WITH data AS (SELECT 1 AS idFROM dualCONNECT BY level < 10000
)
SELECT rownum, TO_CHAR(rownum)
FROM data a, data b
WHERE rownum <= 1000000;1000000 rows created.Statistics
----------------------------------------------------------158 recursive calls15350 db block gets2453 consistent gets0 physical reads23239100 redo size195 bytes sent via SQL*Net to client529 bytes received via SQL*Net from client1 SQL*Net roundtrips to/from client14 sorts (memory)0 sorts (disk)1000000 rows processedSQL>
我們現在重復之前的測試,但這次使用 GTT。
DROP TABLE my_temp_table PURGE;-- Create GTT.
CREATE GLOBAL TEMPORARY TABLE my_temp_table (id NUMBER,description VARCHAR2(20)
)
ON COMMIT PRESERVE ROWS;SET AUTOTRACE ON STATISTICS;-- Populate GTT.
INSERT INTO my_temp_table
WITH data AS (SELECT 1 AS idFROM dualCONNECT BY level < 10000
)
SELECT rownum, TO_CHAR(rownum)
FROM data a, data b
WHERE rownum <= 1000000;1000000 rows created.Statistics
----------------------------------------------------------127 recursive calls15340 db block gets2439 consistent gets0 physical reads2943512 redo size195 bytes sent via SQL*Net to client529 bytes received via SQL*Net from client1 SQL*Net roundtrips to/from client13 sorts (memory)0 sorts (disk)1000000 rows processed
對比日志量
我們可以看到,在使用 GTT 時,我們創建了一個數量級較少的重做,但我們并沒有消除它。
五、其它功能
- 如果對臨時表發出 TRUNCATE 語句,則僅截斷特定于會話的數據。對其他會話的數據沒有影響。
- 臨時表中的數據存儲在臨時表空間的臨時段中。
- 即使數據庫會話異常結束,臨時表中的數據也會在數據庫會話結束時自動刪除。
- 可以在臨時表上創建索引。索引的內容和索引的范圍與數據庫會話相同。
- 可以針對臨時表以及臨時表和永久表的組合創建視圖。
- 臨時表可以有與其關聯的觸發器。
- 導出和導入實用程序可用于傳輸表定義,但不會處理任何數據行。
- 臨時表的統計信息對于所有會話都是通用的。 Oracle 12c 允許會話特定的統計信息。
- 有許多與臨時表相關的限制,但這些限制是特定于版本的。
六、Private Temporary Tables (18c+)
Oracle 18c 中引入了臨時表的新變體。私有臨時表是基于內存的臨時表,根據設置在會話或事務結束時刪除。
#數據庫 #oracle #大頁
🚀 更多數據庫干貨,歡迎關注【安呀智數據坊】
如果你覺得這篇文章對你有幫助,歡迎點贊 👍、收藏 ? 和留言 💬 交流,讓我知道你還想了解哪些數據庫知識!
📬 想系統學習更多數據庫實戰案例與技術指南?
-
📊 實戰項目分享
-
📚 技術原理講解
-
🧠 數據庫架構思維
-
🛠 工具推薦與實用技巧
立即關注,持續更新中 👇