oracle插入大量的數據效率的提高
oracle index 大量數據插入效率問題
---------------------------------------------------------------
--搭建測試環境:
--查看索引是否存在于當前用戶
select * from dba_indexes where owner='system' and index_name='IDX_TEST_INDEX';
DROP TABLE TEST_INDEX;
CREATE TABLE TEST_INDEX
(
USERID NUMBER,
USERNAME VARCHAR2(32),
CREATEDATE DATE
);
DROP TABLE TEST_INDEX_DATA;
CREATE TABLE TEST_INDEX_DATA AS SELECT * FROM TEST_INDEX;
BEGIN
FOR I IN 1 .. 2000000 LOOP
INSERT INTO TEST_INDEX_DATA VALUES (I, '測試索引_' || I, SYSDATE);
END LOOP;
COMMIT;
END;
SELECT COUNT(1) FROM TEST_INDEX_DATA;
SELECT COUNT(1) FROM TEST_INDEX;
----------------------------------------------------------
--沒有索引的時候,直接插入數據
TRUNCATE TABLE TEST_INDEX;--0.078
INSERT INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;--6.25
COMMIT;--0.281
--創建一個索引,然后直接插入數據
TRUNCATE TABLE TEST_INDEX;--2.156
CREATE INDEX IDX_TEST_INDEX ON TEST_INDEX(USERID,USERNAME);--0.125
INSERT INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;--42.688
COMMIT;--0.079
--------------------------------------------------------------
----下面針對有索引的表,在進行大量數據插入的時候測試對比。----
--------------------------------------------------------------
--方案1:先unusable,再truncate,再insert,再rebuild.
ALTER INDEX IDX_TEST_INDEX UNUSABLE;--0.86
TRUNCATE TABLE TEST_INDEX;--2.172
INSERT INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;--43.391
COMMIT;--0.109
ALTER INDEX IDX_TEST_INDEX REBUILD;--17.328
--方案2:先truncate,再unusable,再insert,再rebuild.
TRUNCATE TABLE TEST_INDEX;--1.313
ALTER INDEX IDX_TEST_INDEX UNUSABLE;--0.765
INSERT INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;--8.516
COMMIT;--0.265
ALTER INDEX IDX_TEST_INDEX REBUILD;--10.328
---------------------------------------------------------
---------------------------------------------------------
--方案3:先drop索引,再truncate,在insert,在create索引
DROP INDEX IDX_TEST_INDEX;--0.156
TRUNCATE TABLE TEST_INDEX;--1.735
INSERT INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;--6.188
COMMIT;--0.5
CREATE INDEX IDX_TEST_INDEX ON TEST_INDEX(USERID,USERNAME);--10.812
--方案4:先truncate,再drop索引,在insert,在create索引
TRUNCATE TABLE TEST_INDEX;--2.25
DROP INDEX IDX_TEST_INDEX;--0.109
INSERT INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;--6.157
COMMIT;--0.188
CREATE INDEX IDX_TEST_INDEX ON TEST_INDEX(USERID,USERNAME);--11.078
--------------------------------
--刪除測試環境:
DROP TABLE TEST_INDEX;
DROP TABLE TEST_INDEX_DATA;
------------------------------------
/*綜上所述:
對于有索引的表,在插入大量數據的時候,想要提高性能的話,可以有兩個方法:
1、在插入數據之前,需要將索引給dorp掉,然后等數據插入完成以后,在create上。
2、在插入數據之前,需要將索引給禁用掉,然后等數據插入完成以后,在重新創建上。
需要注意的地方是:
如果你在插入數據之前,需要truncate這個表,然后在插入,那么你對索引禁用的操作一定要放在truncate表語句之后,
如果放在truncate表之前,那么等于你對索引沒有進行任何操作。效率仍然還是那樣慢。
建議使用上述的方案2或3最佳。
如果效率仍然很低,可以考慮使用hint語法。
insert /*+append*/ into TEST_INDEX select * from TEST_INDEX_DATA;
在向TEST_INDEX表中插入數據之前,還可以將表TEST_INDEX修改為nologging,這樣插入數據的時候效率會高一些。
alter table TEST_INDEX nologging.
在創建索引或重建索引的時候,還可以指定nologging,這樣在重建索引的時候,效率會高一些。
alter index IDX_TEST_INDEX rebuild nologging;
不管你的數據運行模式是歸檔日志模式,還會非歸檔日志模式,使用nologging都會提高插入數據的效率。
*/
結合以上個點,最后的實現思路如下:
TRUNCATE TABLE TEST_INDEX;--5.406
ALTER INDEX IDX_TEST_INDEX UNUSABLE;
ALTER TABLE TEST_INDEX NOLOGGING;
INSERT /*+APPEND*/INTO TEST_INDEX SELECT * FROM TEST_INDEX_DATA;
COMMIT;
ALTER INDEX IDX_TEST_INDEX REBUILD NOLOGGING;