应用程序通常使用某种形式的临时数据存储,用于在单个过程中完成复杂的处理过程。通常,这些临时存储被定义为数据库表或PL / SQL表。 从Oracle 8i开始,可以使用全局临时表将临时表的维护和管理委派给服务器。
创建全局临时表
全局临时表中的数据是私有的,因此会话插入的数据只能由该会话访问。 可以为整个会话或仅为当前事务保留全局临时表中的会话特定行。
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(*)
----------
1
SQL>
-- Commit and check contents.
COMMIT;
SELECT COUNT(*) FROM my_temp_table;
COUNT(*)
----------
0
SQL>
相反,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(*)
----------
1
SQL>
-- Reconnect and check contents of GTT.
CONN test/test
SELECT COUNT(*) FROM my_temp_table;
COUNT(*)
----------
0
SQL>
全局临时表和Undo
虽然GTT中的数据被写入临时表空间,但是相关联的undo仍然写入正常的undo表空间,它本身由redo 保护,因此使用GTT不会减少与保护undo表空间相关联的undo和redo 。
以下代码创建一个常规表,填充它并检查事务使用的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 id
FROM dual
CONNECT 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
SQL>
我们现在重复前面的测试,但这次使用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 id
FROM dual
CONNECT 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 6238
SQL>
TRUNCATE TABLE my_temp_table;
我们可以看到,使用的undo没有明显的区别。
Oracle 12c引入了Temporary Undo的概念,允许将GTT的undo写入临时表空间,从而减少undo 和redo
全局临时表和Redo
如果您阅读了上一节,您将已经知道全局临时表和redo之间的关系。 GTT中的数据写入临时表空间,不会被redo直接保护,因此使用GTT可以通过减少redo 生成来提高性能。 不幸的是,在Oracle 12c之前,与GTT相关的所有与DML相关的undo都被写入正常的undo表空间,这个表空间本身由redo保护。 因此,使用GTT减少了redo生成的数量,但不会消除它。 另一个描述这一点的原因是,使用GTT删除直接redo生成,而不是redo导致的间接重做生成。
以下代码创建一个常规表,填充它并检查事务生成的重做数量。
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 id
FROM dual
CONNECT BY level < 10000
)
SELECT rownum, TO_CHAR(rownum)
FROM data a, data b
WHERE rownum <= 1000000;
1000000 rows created.
Statistics
----------------------------------------------------------
106 recursive calls
20119 db block gets
2603 consistent gets
16 physical reads
23039396 redo size
853 bytes sent via SQL*Net to client
987 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1000000 rows processed
SQL>