最近開發專案使用了Oracle,根據總體架構一開始選擇使用Mybatis,發現核心模組用Mybatis效率不夠,切換到jdbc實現,效率大增。Oracle可是個龐然大物,特性多多,絲毫不能馬虎,否則很多雷等著去踩。現在產品試執行階段,回頭總結一下踩過的雷,以後有新的發現會持續更新。
1、關於ROWNUM關鍵字
Oracle返回的某條記錄的ROWNUM並不是不變的,不要依賴於ROWNUM,非要依賴ROWNUM,注意新增ORDER BY分支確定ROWNUM確保不同分頁的資料不會重複。專案一啟動就制訂了約束:不能在專案中應用GROUP BY關鍵字。專案中一次需要彙總統計的輸入表達到幾百萬的資料量級,彙總出來輸出最多幾萬條記錄,因此採用分頁查詢,對分頁資料開啟多個執行緒並行執行計算,做完彙總統計再刪除多有輸入資料,一開始分頁查詢只用了ROWNUM分頁,偶然性的發生彙總出來的資料比輸入資料大的情況,接著定位到了是某些記錄重複進行彙總統計導致。查了Oracle的官方文件,文件描述ROWNUM是在查詢返回來的時候決定值,但不是每次查詢相同記錄都是相同的ROWNUM,可能同一條記錄第一次查詢,ROWNUM在1-1000之間,下次查詢在1001-2000之間。解決方案:在查詢語句中加入ORDER BY ID,其中ID是唯一的,重複統計問題得到解決。
2、關於熱塊競爭問題
一張四五百萬級別的輸入表INPUT1關聯查詢另一張一千萬級別的輸入表INPUT2,關聯查詢使用了索引,執行計劃顯示查詢確實走了索引。一開始從INPUT1獲取n條記錄,對n分成k份,開啟k個執行緒對k份資料併發處理,執行緒內部一進來就執行關聯查詢,通過日誌得知,查詢時而執行的很慢,DBA協調定位,發現併發查詢的多個執行緒之間有相同資料分佈在一個塊中,導致資源等待。解決方案:在關聯查詢的地方做同步塊處理,即應用關鍵字synchronized將關聯查詢包起來。
3、關於共享記憶體超出限制問題
利用Mybatis實現跑批插入,INSERT INTO TB_XXX SELECT XX… FROM (SELECT … FROM DUAL UNION ALL SELECT … FROM DUAL),子查詢中UNION ALL了1000條記錄,在開發庫和測試庫上執行這條語句正常執行,在生產庫中執行了一段時間後,開始丟擲共享記憶體不足異常資訊,原來DBA對開發庫和測試庫沒有設定共享記憶體限制,生產庫設定了共享記憶體限制。解決方案:把1000改成了100,暫時問題解決了。