oracle 插入刪除大量數據時

Oracle的Nologging何時生效 與 批量insert加載數據速度(轉載)

一 非歸檔模式下

D:>sqlplus "/ as sysdba"

數據庫版本爲9.2.0.1.0

SQL*Plus: Release 9.2.0.1.0 - Production on 星期一 8月 14 10:20:39 2006

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.


 


連接到:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

 

當前session產生的redo
SQL> create or replace view redo_size
2 as
3 select value
4 from v$mystat, v$statname
5 where v$mystat.statistic# = v$statname.statistic#
6 and v$statname.name = 'redo size';

視圖已建立。

授權給相應數據庫schema
SQL> grant select on redo_size to liyong;

授權成功。

SQL> shutdown immediate;
數據庫已經關閉。
已經卸載數據庫。
ORACLE 例程已經關閉。

SQL> startup mount;
ORACLE 例程已經啓動。

Total System Global Area 122755896 bytes
Fixed Size 453432 bytes
Variable Size 88080384 bytes
Database Buffers 33554432 bytes
Redo Buffers 667648 bytes
數據庫裝載完畢。

非歸檔模式
SQL> alter database noarchivelog;

數據庫已更改。

SQL> alter database open;

數據庫已更改。

SQL> create table redo_test as
2 select * from all_objects where 1=2;

表已創建。

SQL> select * from sys.redo_size;

VALUE
----------
59488

SQL> insert into redo_test
2 select * from all_objects;

已創建28260行。

SQL> select * from sys.redo_size;

VALUE
----------
3446080

SQL> insert /*+ append */ into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
3458156

可以看到insert /*+ append */ into方式redo產生很少.
SQL> select 3446080-59488,3458156-3446080 from dual;

3446080-59488 3458156-3446080
------------- ---------------
3386592 12076

 

將表redo_test置爲nologging狀態.
SQL> alter table redo_test nologging;

表已更改。

SQL> select * from sys.redo_size;

VALUE
----------
3460052

SQL> insert into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
6805876

SQL> insert /*+ append */ into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
6818144

非歸檔模式下表的nologging狀態對於redo影響不大
SQL> select 6805876-3460052,6818144-6805876 from dual;

6805876-3460052 6818144-6805876
--------------- ---------------
3345824 12268


結論: 在非歸檔模式下通過insert /*+ append */ into方式批量加載數據可以大大減少redo產生.

 

 

 

 

二 歸檔模式下


SQL> shutdown immediate;
數據庫已經關閉。
已經卸載數據庫。
ORACLE 例程已經關閉。
SQL> startup mount;
ORACLE 例程已經啓動。

Total System Global Area 122755896 bytes
Fixed Size 453432 bytes
Variable Size 88080384 bytes
Database Buffers 33554432 bytes
Redo Buffers 667648 bytes
數據庫裝載完畢。
SQL> alter database archivelog;

數據庫已更改。

SQL> alter database open;

數據庫已更改。

SQL> conn liyong
請輸入口令:
已連接。


將表redo_test重新置爲logging
SQL> alter table redo_test logging;

表已更改。

SQL> select * from sys.redo_size;

VALUE
----------
5172

SQL> insert into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
3351344

SQL> insert /*+ append */ into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
6659932

可以看到在歸檔模式下,且表的logging屬性爲true,insert /*+ append */ into這種方式也會紀錄大量redo
SQL> select 3351344-5172,6659932-3351344 from dual;

3351344-5172 6659932-3351344
------------ ---------------
3346172 3308588


將表置爲nologging

SQL> alter table redo_test nologging;

表已更改。

SQL> select * from sys.redo_size;

VALUE
----------
6661820

SQL> insert into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
10008060

SQL> insert /*+ append */ into redo_test
2 select * from all_objects;

已創建28260行。

SQL> commit;

提交完成。

SQL> select * from sys.redo_size;

VALUE
----------
10022852

可以發現在歸檔模式,要設置表的logging屬性爲false,才能通過insert /*+ append */ into大大減少redo產生.
SQL> select 10008060-6661820,10022852-10008060 from dual;

10008060-6661820 10022852-10008060
---------------- -----------------
3346240 14792

 

結論: 在歸檔模式下,要設置表的logging屬性爲false,
才能通過insert /*+ append */ into大大減少redo.

 

 

 

 

三 下面我們再看一下在歸檔模式下,幾種批量insert操作的效率對比.

 

redo_test表有45W條記錄

SQL> select count(*) from redo_test;

COUNT(*)
----------
452160


1 最常見的批量數據加載 25秒

SQL> create table insert_normal as
2 select * from redo_test where 0=2;

表已創建。

SQL> set timing on

SQL> insert into insert_normal
2 select * from redo_test;

已創建452160行。

提交完成。
已用時間: 00: 00: 25.00


2 使用insert /*+ append */ into方式(這個的原理可以參見<<批量DML操作優化建議.txt>>),但紀錄redo. 17.07秒
SQL> create table insert_hwt
2 as
3 select * from redo_test where 0=2;

表已創建。
SQL> insert /*+ append */ into insert_hwt
2 select * from redo_test;

已創建452160行。

提交完成。
已用時間: 00: 00: 17.07


3 使用insert /*+ append */ into方式,且通過設置表nologging不紀錄redo.

SQL> create table insert_hwt_with_nologging nologging
2 as
3 select * from redo_test where 2=0;

表已創建。

/*
或者通過
alter table table_name nologging設置
*/

SQL> insert /*+ append */ into insert_hwt_with_nologging 11.03秒
2 select * from redo_test;

已創建452160行。

提交完成。
已用時間: 00: 00: 11.03

 

總結:

我們看到對於批量操作,如果設置表nologging,可以大大提高性能.原因就是Oracle沒有紀錄DML所產生的redo.
當然,這樣會影響到備份。nologging加載數據後要做數據庫全備.

下面我又試了試insert into XXX values (XXX)能不能少產生redo,做了試驗發現,不行的,下面的過程.
SQL> select * from v$version where rownum archive log list;
Database log mode No Archive Mode
Automatic archival Disabled
Archive destination USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence 17
Current log sequence 19

SQL> create or replace view redo_size
2 as
3 select value
4 from v$mystat, v$statname
5 where v$mystat.statistic# = v$statname.statistic#
6 and v$statname.name = 'redo size';

View created.

SQL> grant select on redo_size to ljg;

SQL> conn ljg/ljg
Connected.

SQL> create table redo_test as
2 select * from all_objects where 1=2;

SQL> CREATE OR REPLACE PROCEDURE p_loging
2 as
3 CURSOR c_a IS
4 SELECT * FROM all_objects;
5
6 BEGIN
7 FOR x IN c_a LOOP
8 INSERT INTO REDO_TEST
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJE CT_ID,
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);
11 END LOOP;
12 COMMIT;
13
14 END;
15 /

Procedure created.

SQL> CREATE OR REPLACE PROCEDURE p_nologing
2 as
3 CURSOR c_a IS
4 SELECT * FROM all_objects;
5
6 BEGIN
7 FOR x IN c_a LOOP
8 INSERT /*+ APPEND */ INTO REDO_TEST
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJECT_ID,
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);
11 END LOOP;
12 COMMIT;
13
14 END;
15 /

Procedure created.

SQL> select * from sys.redo_size;

VALUE
----------
85940

SQL> exec p_loging;

PL/SQL procedure successfully completed.

SQL> select * from sys.redo_size;

VALUE
----------
15273968

SQL> exec p_nologing;

PL/SQL procedure successfully completed.

SQL> select * from sys.redo_size;

VALUE
----------
30411272

SQL> select 15273968- 85940 logging,30411272-15273968 nologging from dual;

LOGGING NOLOGGING
---------- ----------
15188028 15137304

可以看到nologging和logging產生的redo差不多.

下面我又試了試insert into XXX values (XXX)能不能少產生redo,做了試驗發現,不行的,下面的過程.
SQL> select * from v$version where rownum archive log list;
Database log mode No Archive Mode
Automatic archival Disabled
Archive destination USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence 17
Current log sequence 19

SQL> create or replace view redo_size
2 as
3 select value
4 from v$mystat, v$statname
5 where v$mystat.statistic# = v$statname.statistic#
6 and v$statname.name = 'redo size';

View created.

SQL> grant select on redo_size to ljg;

SQL> conn ljg/ljg
Connected.

SQL> create table redo_test as
2 select * from all_objects where 1=2;

SQL> CREATE OR REPLACE PROCEDURE p_loging
2 as
3 CURSOR c_a IS
4 SELECT * FROM all_objects;
5
6 BEGIN
7 FOR x IN c_a LOOP
8 INSERT INTO REDO_TEST
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJE CT_ID,
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);
11 END LOOP;
12 COMMIT;
13
14 END;
15 /

Procedure created.

SQL> CREATE OR REPLACE PROCEDURE p_nologing
2 as
3 CURSOR c_a IS
4 SELECT * FROM all_objects;
5
6 BEGIN
7 FOR x IN c_a LOOP
8 INSERT /*+ APPEND */ INTO REDO_TEST
9 VALUES(x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME, x.OBJECT_ID, x.DATA_OBJECT_ID,
10 x.OBJECT_TYPE, x.CREATED, x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY, x.GENERATED, x.SECONDARY);
11 END LOOP;
12 COMMIT;
13
14 END;
15 /

Procedure created.

SQL> select * from sys.redo_size;

VALUE
----------
85940

SQL> exec p_loging;

PL/SQL procedure successfully completed.

SQL> select * from sys.redo_size;

VALUE
----------
15273968

SQL> exec p_nologing;

PL/SQL procedure successfully completed.

SQL> select * from sys.redo_size;

VALUE
----------
30411272

SQL> select 15273968- 85940 logging,30411272-15273968 nologging from dual;

LOGGING NOLOGGING
---------- ----------
15188028 15137304

可以看到nologging和logging產生的redo差不多.

在ITPUB中問到可以用BULK COLLECT 來減少insert into values的redo.
CREATE OR REPLACE PROCEDURE p_BulkAdd
AS
TYPE Tredo_test IS TABLE OF REDO_TEST%ROWTYPE;
V_REDO_TEST Tredo_test;
BEGIN
SELECT * BULK COLLECT INTO V_REDO_TEST FROM ALL_OBJECTS;
FORALL X IN V_REDO_TEST.FIRST..V_REDO_TEST.LAST
INSERT INTO REDO_TEST VALUES V_REDO_TEST(X);
END;
/

SQL> select * from sys.redo_size;

VALUE
----------
30411272

SQL> exec p_bulkadd;

PL/SQL procedure successfully completed.

SQL> select * from sys.redo_size;

VALUE
----------
35050796

SQL> select 35050796-30411272 from dual;

35050796-30411272
-----------------
4639524

這個做的確是少了很多redo.是一個方法.

 

 

 

發佈了47 篇原創文章 · 獲贊 0 · 訪問量 3087
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章