并行在平時工作中可能不是很注意,因為有時候即使設定了parallel 相關的hint,感覺性能也好不到哪去。這是我以前的感覺。
今天通過一個案例來分享一下通過parallel來使資料加載的速度達到極速提升。
現有一個很讓人頭疼的表,裡面還有clob字段,通過exp/imp來導出導入資料,導出慢還可以接受,導入的速度大概在一秒鐘1000條的速度,對于千萬,上億的資料來說,簡直就是噩夢。對于資料泵,也測試了各種可能的改進方法。但是效果都不讓人滿意,首先就是對于undo的消耗極大,還有impdp中parallel選項因為clob無法激活。在測試環境中反複測試,時間大概保持在2個小時的樣子(資料量是5千萬),而且還得不斷的去檢視undo的使用率,有一次測試中還報了undo空間不足的錯誤,整個資料導入得重頭再來,而且還使得高水位線受到影響。
個人反複的嘗試,最後使用外部表來進行資料的分批導入,這樣能夠降低undo使用率,對于進度也比較好把握,比如對于大表big_table,我生成了20個外部表,把big_table裡的資料分攤到了20個外部表中,這樣每個外部表做完insert之後,馬上commit,可以減少undo使用競争。測試環境中測試,時間在40~60分鐘左右,剛開始的時候速度很快,一分鐘将近160萬的資料加載速度,但是到後面速度就開始逐漸降下來了。最後150萬的資料基本在5分鐘左右。
一方面是外部原因,另一方面和資料庫内部的機理也有關聯,有些塊不會很快的釋放。
使用外部表Insert的方式性能要好一些,但是得改進一些地方,尤其是對于大表來說,parallel比想象中的效果要好很多,
首先來看一下一般的資料插入速度。速度在40秒左右。為了保證測試的可評估性,我每次都會換一個資料量基本一緻的外部表來插入資料。
SQL> insert into big_table select *from big_table_ext_33;
820374 rows created.
Elapsed: 00:00:40.80
SQL> commit;
嘗試使用append方式插入資料,表big_table已經設定為nologging模式,有4個local partitioned 的index,都是logging模式。
速度一下子提升了不少達到了16秒。
SQL> insert /*+append*/ into big_table select *from big_table_ext_30;
960461 rows created.
Elapsed: 00:00:16.11
然後繼續換一個表,使用parallel hint來插入資料。但是時間好像沒有任何提升。
SQL> insert /*+append parallel(big_table 8) */ into big_table select *from big_table_ext_2;
988140 rows created.
Elapsed: 00:00:16.14
這個時候可以使用v$pq_sesstat來檢視使用parallel被啟用了。
SQL> select * from v$pq_sesstat;
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- -------------
Queries Parallelized 0 0
DML Parallelized 0 0
DDL Parallelized 0 0
DFO Trees 0 0
Server Threads 0 0
Allocation Height 0 0
Allocation Width 0 0
Local Msgs Sent 0 0
Distr Msgs Sent 0 0
Local Msgs Recv'd 0 0
Distr Msgs Recv'd 0 0
11 rows selected.
可以看到parallel的hint被oracle給忽略了。parallel dml的優先級是session >hint> object
是以繼續設定session級的hint,啟用parallel,這個時候如果想保證啟用paralell可以使用force選項。
SQL> alter session force parallel dml parallel 8;
Session altered.
Elapsed: 00:00:00.00
再次插入資料,時間一下子降低到了6秒鐘。
SQL> insert /*+append parallel(big_table 8) */ into big_table select *from big_table_ext_31;
930198 rows created.
Elapsed: 00:00:06.49
清空資料,稍候繼續插入資料,來看看是否parallel被啟用了。
SQL> truncate table big_table;
Table truncated.
Elapsed: 00:00:01.34
DML Parallelized 0 1
DFO Trees 0 1
Local Msgs Sent 0 16191
Local Msgs Recv'd 0 16191
将近100萬的資料在6秒鐘導入了,如果是5000萬的資料大概需要6分鐘左右的時間,來簡單驗證一下
做一個大的資料插入。大概用了7分鐘的時間,速度還是不錯的。
SQL> insert /*+append parallel(big_table 8) */ into big_table select *from big_table_ext;
58303757 rows created.
Elapsed: 00:07:26.48
Commit complete.
Elapsed: 00:00:01.92
DML Parallelized 1 2
DFO Trees 1 2
Server Threads 16 0
Allocation Height 8 0
Allocation Width 1 0
Local Msgs Sent 994995 1011186
Local Msgs Recv'd 994995 1011186
在資料導入的過程中,啟用了相應的并行程序。
26388 testdbn 15 0 11.5g 1.4g 1.1g S 38.3 0.4 2:41.80 ora_p012_TESTDB
26394 testdbn 15 0 11.5g 1.4g 1.1g S 38.3 0.4 2:40.87 ora_p015_TESTDB
26380 testdbn 15 0 11.5g 1.4g 1.2g S 37.6 0.4 3:50.61 ora_p008_TESTDB
26390 testdbn 15 0 11.5g 1.4g 1.1g S 37.6 0.4 2:44.64 ora_p013_TESTDB
26392 testdbn 15 0 11.5g 1.4g 1.1g S 37.3 0.4 2:43.63 ora_p014_TESTDB
26382 testdbn 15 0 11.5g 1.4g 1.1g S 37.0 0.4 2:43.43 ora_p009_TESTDB
7080 testdbn 16 0 11.3g 68m 28m S 9.7 0.0 2:38.05 ora_arc2_TESTDB
4101 testdbn 15 0 11.2g 6.1g 6.1g S 6.1 1.7 10:54.46 ora_dbw1_TESTDB
4105 testdbn 15 0 11.2g 6.1g 6.1g S 6.1 1.7 11:27.73 ora_dbw3_TESTDB
4099 testdbn 15 0 11.2g 6.1g 6.1g R 5.8 1.7 11:49.40 ora_dbw0_TESTDB
4103 testdbn 15 0 11.2g 6.1g 6.1g S 4.8 1.7 10:47.55 ora_dbw2_TESTDB
是以在cpu資源充足的情況下,啟用并行也是一個不錯的選擇。