Proc 是Oracle提供的一種資料庫操作的AP。它是基於ESql技術的,需要預編譯後才可以變成普通c代碼,非常不直觀,使用起來不太方便,閱讀也存在困難。 因為這些問題導致程式員平時開發中會出現一些Proc操作存在效率低下的情況,本文介紹一些Proc一些編譯經驗,希望能給大家提供參考。 下麵以一個 ...
Proc 是Oracle提供的一種資料庫操作的AP。它是基於ESql技術的,需要預編譯後才可以變成普通c代碼,非常不直觀,使用起來不太方便,閱讀也存在困難。
因為這些問題導致程式員平時開發中會出現一些Proc操作存在效率低下的情況,本文介紹一些Proc一些編譯經驗,希望能給大家提供參考。
下麵以一個簡單需求進行舉例說明:
要求把DB1裡面一張數據表tbl_hch_test的數據導出到DB2的同名錶。
最快的方法當然是使用oracle的數據泵工具進行壓縮導出再導入,但expdp/impdp對資料庫環境有特別要求,所以我們需要使用Proc編程,先從DB1取出數據,再insert到Db2裡面。
簡單實現:
打開一個游標,從DB1迴圈FETCH數據出來,再使用sprintf拼裝成insert語句,到DB2使用exec sql指令執行插入並提交資料庫。
優化:
雖然上面的做法可以完成需求,但在效率上存在不優化空間。下麵依次進行介紹:
1 使用綁定變數代替sprintf拼裝sql
實踐證明sprintf函數在對效率要求比較高的場景下容易成為性能瓶頸,使用綁定變數可以避免sprintf調用。
並且,由於資料庫裡面執行的sql是相同的,不需要每次重新分析sql生成執行計劃,也能大大減輕資料庫負擔,提高執行效率。
2 對insert語句進行預編譯,一次編譯多次執行,避免使用隱性游標,每次都要重新編譯。
同上,預編譯是比較消耗cpu的操作。如果sql相同,可以復用游標,減少性能開支。
3 使用批量操作,每次取數和插入數據都使用數組進行綁定。
批量操作可以減少客戶端與伺服器之間交互次數,加快操作數據。
4 適當加大事務提交間隔(insert多行記錄commit一次)
Oracle提交資料庫事務時需要將日誌從記憶體刷回磁碟並等待磁碟操作完成才返回,提高事務提交間隔可以減少等待消耗。
優化前後效率測試對比:
相同的操作,從23s降低到1.3s
其它提高效率措施:
以上是在編程上的一些優化,結合oracle一些特性,速度還能再提升,簡單介紹幾個優化技巧:
1 先刪除目標表索引,insert完數據後再重建
2 關閉表的日誌, 減少redo日誌,alter table tbl_hch_test nologing。裝載完數據再改回來。
3 使用append HINT,在高水位上面直接插入數據,加快插入速度。
4 使用並行(parallel)查詢,或者使用分區查詢(select * from tab parttion(par_name))加快查詢速度。
5 如果可能,儘量在資料庫伺服器上執行程式,減少網路傳輸開銷
關鍵代碼參考:
另外,附上幾個平時使用Proc容易出現誤區。
1 使用char數組保存資料庫varchar2類型欄位的值
Proc的char數組對應的資料庫類型是char,varchar結構體對應的類型才是varchar2。使用char數組保存資料庫varchar2類型欄位的值,會導致取出的數據像char類型一樣,在末尾自動添加空格。
解決方法可以使用EXEC SQL VAR/ EXEC SQL TYPE同等化變數或者數據類型。或者在預編譯時指定CHAR_MAP=string一勞永役
2 需要註意proc的一些命令是預編譯命令,只在預編譯期間生效,與C語言的巨集十分相似。例如以下命令:。
EXEC SQL CONTEXT USE
ESEC SQL Whenever Sqlerror Do
下麵舉一個常見的錯誤進行說明:
要完全搞明白proc的原理,建議多分析.pc文件與porc預編譯後生成的.c文件代碼區別。
3 proc指針變數
Proc可以正確識別指針與普通變數,使用指針做為綁定變數與使用普通變數的方法一樣,在變數前面加上冒號即可。
官方文檔是這樣說的:
有一些程式員不清楚怎麼在proc使用指針,會使用memcpy把數據複製多一遍,增加無謂消耗。
4 proc與C語言巨集
Proc能識別C語言的一些簡單的巨集,但如果有複雜的巨集(如不定參數巨集),proc在預編譯時會報錯。
此時可以考慮使用gcc –E先對.pc文件進行預處理,之後再使用proc進行預編譯。
如果對於proc編程還有什麼其它疑惑的地方,歡迎大家與我討論,或者查閱官方幫助文檔。《Oracle Proc官方文檔.pdf》