客服微信
本文为云贝教育 刘峰 原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。
应用程序通常使用某种形式的临时数据存储来处理过于复杂而无法一次性完成的流程。通常,这些临时存储被定义为数据库表或 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(*) ---------- 1 SQL> -- 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(*) ---------- 1 SQL> -- Reconnect and check contents of GTT. CONN test/test SELECT COUNT(*) FROM my_temp_table; COUNT(*) ---------- 0 SQL>
虽然 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 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
现在我们重复前面的测试,但这次使用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>
我们可以看到,所使用的undo没有显着差异。
Oracle 12c引入了临时撤销的概念,允许将GTT的撤销写入临时表空间,从而减少了撤销和重做。
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 id FROM dual CONNECT BY level < 10000 ) SELECT rownum, TO_CHAR(rownum) FROM data a, data b WHERE rownum <= 1000000; 1000000 rows created. Statistics ---------------------------------------------------------- 158 recursive calls 15350 db block gets 2453 consistent gets 0 physical reads 23239100 redo size 195 bytes sent via SQL*Net to client 529 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 14 sorts (memory) 0 sorts (disk) 1000000 rows processed 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; SET AUTOTRACE ON STATISTICS; -- 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; 1000000 rows created. Statistics ---------------------------------------------------------- 127 recursive calls 15340 db block gets 2439 consistent gets 0 physical reads 2943512 redo size 195 bytes sent via SQL*Net to client 529 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 13 sorts (memory) 0 sorts (disk) 1000000 rows processed
我们可以看到,在使用 GTT 时,我们创建了一个数量级较少的重做,但我们并没有消除它。
Oracle 18c 中引入了临时表的新变体。私有临时表是基于内存的临时表,根据设置在会话或事务结束时删除。