Use a direct path load
something like this:
ops$tkyte%ORA11GR2> create sequence s;
Sequence created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> create table stage
2 as
3 select *
4 from all_objects
5 where mod(object_id,2) = 0
6 /
Table created.
ops$tkyte%ORA11GR2> create table t
2 as
3 select 0 pk, a.*
4 from all_objects a
5 where 1=0
6 /
Table created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> insert /*+ append */
2 into t ( pk, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
3 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,
4 TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME)
5 select s.nextval, x.*
6 from ( select OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
7 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,
8 TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME
9 from STAGE
10 MINUS
11 select OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
12 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,
13 TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME
14 from t ) x
15 /
36649 rows created.
ops$tkyte%ORA11GR2> commit;
Commit complete.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> drop table stage;
Table dropped.
ops$tkyte%ORA11GR2> create table stage as select * from all_objects;
Table created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> insert /*+ append */
2 into t ( pk, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
3 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,
4 TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME)
5 select s.nextval, x.*
6 from ( select OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
7 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,
8 TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME
9 from STAGE
10 MINUS
11 select OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
12 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,
13 TEMPORARY, GENERATED, SECONDARY, NAMESPACE, EDITION_NAME
14 from t ) x
15 /
36555 rows created.
ops$tkyte%ORA11GR2> commit;
Commit complete.
the nice thing about minus is that it will deal with NULLs. I'm assuming you want to match on the entire record here. If not, MERGE /*+ APPEND */ will work nicely as well - perhaps better than MINUS.
that will direct path load the data - bypassing UNDO, *optionally* bypassing redo (make sure you understand the ramifications of this!!) and maintaining any existing indexes as efficiently as possible. Also, it will bypass the inefficiencies of the buffer cache and just write directly to datafiles.
You may want to enable parallel query whilst doing this if you have the free cpu, memory and IO bandwidth to do so.