[英]How to make my Oracle update/insert action through Java faster?
我在公司面臨一個問題 - 我們的程序速度不夠快。 更具體地說,我們是電信公司,這個程序處理我們城市每個手機用戶的電話/互聯網服務交易。 由於iphone用戶下載內容的數量太多,我們的程序無法足夠快地處理它們。
情況是,用戶進行的交易量是我們程序處理的交易量的兩倍。 程序的大部分運行時間都由數據庫事務控制。
我通過互聯網搜索並瀏覽了一些關於數據庫中Java性能的網站(例如: http : //www.javaperformancetuning.com/tips/rawtips.shtml ),但我找不到適合我們的建議。
這些建議不適用/已經使用過,例如:
1.使用准備好的陳述。 使用參數化SQL
已經使用過准備好的聲明。 每次都會通過清除參數和設置參數使用不同的參數。
2.調整SQL以最小化返回的數據(例如,不是'SELECT *')。
當然,已經使用過。
3.使用連接池。
我們在程序執行期間保持一個連接。 我懷疑匯集無法解決問題,因為我們的程序充當1個用戶,因此並發訪問DB沒有問題。 如果你們有人認為合並是好的,請告訴我原因。 謝謝。
4.嘗試組合查詢和批量更新。
不能這樣做。 每個查詢/插入/更新都取決於數據庫的信息。 例如,我們在DB中查找客戶端的信息,如果我們找不到他的用法,我們會將用法插入到DB中,否則我們會更新。
5.完成后關閉資源(Connections,Statements,ResultSet)
當然。
6.選擇最快的JDBC驅動程序。
我不知道。 我在互聯網上搜索可用的驅動程序類型,我很困惑。 我們使用oracle.jdbc.driver.OracleDriver
,我們使用thin而不是oci,這就是我所知道的。 另外,我們的程序是雙層方式(java < - > oracle)
7.關閉自動提交
已經做到了。
期待任何幫助。
4.嘗試組合查詢和批量更新。
不能這樣做。 每個查詢/插入/更新都取決於數據庫的信息。 例如,我們在DB中查找客戶端的信息,如果我們找不到他的用法,我們會將用法插入到DB中,否則我們會更新。
如果您是從Java應用程序執行此操作,則可以通過一次往返在數據庫中執行此操作來提高性能。 有兩種方法:
1)使用SQL MERGE語句
2)編寫存儲過程來執行插入或更新邏輯,然后從Java調用它。
我假設您說的是目前Java邏輯的工作方式如下:
// Pseudocode
execute SQL 'select count(*) from mytable where id=?'
if result = 0 then
execute SQL 'insert into mytable (id,a,b,c) values (?,?,?,?)';
else
execute SQL 'update mytable set a=?, b=?, c=? where id=?';
end if;
這意味着對數據庫進行2次單獨的往返:一次是檢查記錄是否存在,另一次是根據需要插入或更新。
替代方案是:
1)使用SQL MERGE語句:
// Pseudocode
execute SQL 'merge into mytable t using (select ? id, ? a, ? b, ? c from dual) s
on (t.id = s.id)
when matched then update set t.a = s.a, t.b = s.b, t.c = s.c
when not matched then insert (id, a, b, c)
values (s.id, s.a, s.b, s.c)';
MERGE語句起初有點令人生畏,特別是在這樣的情況下你必須使用Oracle的“雙”表。
2)使用存儲過程:
// Pseudocode
execute SQL 'begin mytable_package.insert_or_update
(p_id => ?, p_a => ?, p_b => ?, p_c => ?); end;'
存儲過程在名為mytable_package的包中看起來像
procedure insert_or_update (p_id mytable.id%type
,p_a mytable.a%type
,p_b mytable.a%type
,p_c mytable.a%type
)
is
begin
update mytable
set a = p_a, b = p_b, c = p_c
where id = p_id;
if sql%rowcount = 0 then
insert into mytable (id, a, b, c) values (p_id, p_a, p_b, p_c);
end if;
end;
檢查你的索引! 更新性能不佳可能是外鍵約束的結果,其中外鍵上的索引在引用表上缺失。
4)嘗試組合查詢和批量更新。
不能這樣做。 每個查詢/插入/更新都取決於數據庫的信息。 例如,我們在DB中查找客戶端的信息,如果我們找不到他的用法,我們會將用法插入到DB中,否則我們會更新。
我想到了兩件事:
執行UPDATE語句並檢查ExecuteUpdate()的結果; 僅當它為零時,執行INSERT。 為您保存一個SELECT語句。
始終(可能批量)插入中間表,稍后使用MERGE語句更新您的使用表。
5)完成后關閉資源(Connections,Statements,ResultSet)
盡可能長時間保持連接打開(即永久關閉服務器),准備一次PreparedStatement並重復使用。
在寫入數據庫之前先進行一些聚合。 現在生成交易的手機用戶可能會在幾秒鍾內生成另一個交易。 使用哈希表來聚合當前使用情況,並在一分鍾左右后將其寫入數據庫。
獲取Professional Oracle Programming的副本。
在2005年,它似乎有點舊,但在優化性能方面,Oracle並沒有大幅改變。 我自己有這本書,並且已經使用它的建議來加速許多應用程序看似棘手的性能問題。 得到它。 閱讀。 做吧。
那么在等待快遞時你能做些什么呢?
這應該足以讓你牢牢掌握失敗的原因以及解決方法。
首先, 您需要DBA在您身邊告訴您實際花費的時間。 您可以在客戶端快速閃電,並且在設置關鍵索引之前仍然需要很長的事務處理時間。
自從我使用Java + Oracle已經八年了,但我沒有找到oci驅動程序(在DLL中使用本機驅動程序)比使用瘦驅動程序(全部用Java編寫)快得多。
快速解決方法可以為您提供喘息空間,可以生成一次包含1000或10000個事務的文本文件,並讓“SQLLDR”將批處理注入數據庫。 也許更多。 正確調用SQLLDR是最快的事情,它會讓你有時間正確地執行它。
您是否為每次執行啟動JVM的新實例? 您能詳細說明應用程序的性質(即如何調用它,觸發調用的內容等)。 根據您的描述,它聽起來並不像Java和DB問題。 聽起來好像是某種數據庫索引問題或其他設計問題。 您正在使用的SQL命令的性質是什么? 你有沒有定時或描述這些電話,看看有些人比其他人要長嗎?
您可以將工作負載划分為使用多個會話到數據庫嗎? 有很多往返數據庫的往返導致延遲。 如果表的結構正確,它們可以毫無問題地處理多個並發插入/更新(檢查重插入表的INITRANS屬性是否與執行插入的並發會話數相同)。 我認為這將是贏得應用性能最簡單的方法。 正在使用哪個版本的數據庫? 你能得到ADDM報告嗎? 他們可以立即告訴您 - 數據庫中的問題是什么 - 如果有的話。 應用服務器有足夠的CPU資源嗎? 如果沒有,這是將負載分成多個會話的另一個原因,在這種情況下分成多個應用服務器。 如果沒有statspack報告或 - 最好是 - ADDM報告,很難說出問題出在哪里。
羅納德,我希望這會有所幫助。
如果您希望將DBA的參與保持在最低限度,您至少可以要求登錄以訪問在測試服務器上運行的Oracle Enterprise Manager。 在OEM中,您實際上可以看到哪些操作需要很長時間。 OEM還會嘗試通過建議提高性能的方法來幫助您,例如添加索引或更改查詢結構。 希望OEM至少可以為您提供可靠的理由,要求DBA進一步參與。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.