练习 DOUBLE INSERT

 

 练习 DOUBLE INSERT

目标:从一张表取数据插入到另一张表中,此外需要为插入的目标表做一个应用级的日志表,也就是说在插入目标表的同时,还需要将相同的数据插入到日志表中。

在案例一中,我们给出了CREATE TRIGGEROPEN CURSOR ;BULK INTO VARIABLE; DOUBLE INSERT; INSERT ALL 等方案。每个方案中也阐述了他的优缺点。

其中在DOUBLE INSERT,为了保证数据的一致性,又给出了四种思路,它们分别是锁,串行,临时表和as of 查询。下面将展现这四种思路SQL的展现。

当然DOUBLE INSERT 除了一致性的问题,还有原子性的问题,即有可有目标表 日志表只成功了其它一个,或都没成功。关于原子性的问题。暂不讨论。

 

1.1思路一

Drop table test;

Drop table T_ORG;

DROP TABLE T_LOG;

create table test as select * from all_objects ;

create table T_ORG as select * from all_objects  WHERE 1=2;

create table T_LOG as select * from all_objects WHERE 1=2;

 

 

#   --共享行专用(SRX):阻止其他事务操作,其会会话不能对test表进行DML操作

SQL> lock table t in exclusive mode nowait;  

 

Locked Object:

 

OWNEROS_USER_NAME  OBJECT_NAME   SIDSERIAL# LOCKED_MODE LOGON_TIM

------- ------------- ----------------- ---------- ----------- -------

SYS     oracle        TEST       18         17           6 26-APR-19

 

 

SYS@test>INSERT INTO T_ORG SELECT * FROM TEST;

72183 rows created.

SYS@test>INSERT INTO T_LOG SELECT * FROM TEST;

72183 rows created.

 

新开一个窗口执行delete 操作产生等待:

SYS@test2>delete from test where OBJECT_ID <10 ;  

直到原来窗口事务结束。

SYS@test>COMMIT ;

 

问题:影响其它事务

 

1.2思路二 串行事务面临的问题 ora-01555

Drop table test;

Drop table T_ORG;

DROP TABLE T_LOG;

create table test as select * from all_objects ;

create table T_ORG as select * from all_objects  WHERE 1=2;

create table T_LOG as select * from all_objects WHERE 1=2;

 

SYS@test>create undo tablespace undotbs datafile '/u01/app/oracle/oradata/test/undotbs.dbf' size 1M ;

Tablespace created.

 

SYS@test>alter system set undo_tablespace=undotbs;

 

SYS@test>show parameter undo ;

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ---------------------

undo_management                      string      AUTO

undo_retention                       integer     900

undo_tablespace                      string      UNDOTBS

 

 

declare

begin

INSERT INTO T_ORG SELECT * FROM TEST;

INSERT INTO T_LOG SELECT * FROM TEST;

Commit ;

end ;

/

 

*

ERROR at line 1:

ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS'

ORA-06512: at line 3

 

SYS@test>select count(*) from T_ORG ;

  COUNT(*)

----------

         0

 

问题:UNDO 空间不足时,会报ORA-30036
     
如果UNDO空间被覆盖会报ORA-01555

 

1.3思路三 临时表

Drop table test;

Drop table T_ORG;

DROP TABLE T_LOG;

create table test as select * from all_objects ;

create table T_ORG as select * from all_objects  WHERE 1=2;

create table T_LOG as select * from all_objects WHERE 1=2;

 

SYS@test>alter system set undo_tablespace=UNDOTBS1;

 

创建会话级别临时表:

SYS@test> create global temporary table temp1 on Commit Preserve Rows  as select * from all_objects where 1=2   ;

 

把数据写入到临时表:

SYS@test>INSERT INTO temp1 SELECT * FROM all_objects;

72186 rows created.

 

SYS@test>INSERT INTO T_ORG SELECT * FROM temp1;

72186 rows created.

SYS@test>INSERT INTO T_LOG SELECT * FROM temp1;

72186 rows created.

 

问题:相关于写了三次,读了三次,对性能影响较大

 

1.4思路四 AS OF 查询

Drop table test;

Drop table T_ORG;

DROP TABLE T_LOG;

create table test as select * from all_objects ;

create table T_ORG as select * from all_objects  WHERE 1=2;

create table T_LOG as select * from all_objects WHERE 1=2;

 

SYS@test>select current_scn from v$database  ;

CURRENT_SCN

-----------

     975216

 

 

SYS@test>INSERT INTO T_ORG SELECT * FROM test as of scn 975216;

72184 rows created.

 

SYS@test>INSERT INTO T_LOG SELECT * FROM test as of scn 975216;

72184 rows created.

 

前提是你要提前查询SCN 时间,而且还是查询插入了2次。

 

针对以上的问题,最好的解决方案是利用ORACLE insert all

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">





原文地址:https://www.cnblogs.com/cqdba/p/bdbfe7a50561d41f8c43fb70fceecfec.html