我需要創建一個約需要插入數據庫的50K記錄列表。Java列表v/s數據庫列表哪一個很貴?
我能想到的兩種方法是在性能
方面更好的辦法- 存儲過程,它接受這些對象的名單,將它們插入Java和使用每一條記錄調用數據庫插入
- 建構列表MyBatis的
我需要創建一個約需要插入數據庫的50K記錄列表。Java列表v/s數據庫列表哪一個很貴?
我能想到的兩種方法是在性能
方面更好的辦法表現最好的將來自插入語句的批次,如下所示:
insert into my_table (c1, c2, c3) values
(v1, v2, v3),
(v4, v5, v6),
...
如果您將它分成50,000個插入語句,您將獲得更差的性能。插入語句越少越好。每個插入語句都需要mysql解析查詢,並獲取並釋放必要表上的鎖,更不用說啓動和提交事務。例如,如果您可以在500行的100個塊中完成此操作,則會削減49,900x這個開銷。
如果您想使用LOAD DATA INFILE命令,您甚至可以進一步提高性能,但這會使事情變得複雜一些,根據您的具體要求可能不值得。
這是無效的oracle語法,儘管你可以通過各種方式實現類似的結果,例如'insert into my_table(c1,c2,c3)select double,union的所有v1,v2,v3所有從雙重聯合中選擇v4,v5,v6所有......'或'將所有值都插入my_table(c1,c2,c3)值(v1,v2,v3)到my_table(c1,c2,c3)值(v4,v5,v6)中... select * from dual 「一切都顯得更加冗長,但他們確實達到了將所有內容都保存在一個聲明中的預期結果。 – Sentinel
你最好的表現將是某種形式的批量插入不管是
多記錄插入:使用本地PL
insert into your_table(c1,c2,c3)
select v1, v2, v3 from dual union all
select v4, v5, v6 from dual union all
...
select vN, vO, vP from dual;
或
insert all
into your_table(c1,c2,c3) values (v1,v2,v3)
into your_table(c1,c2,c3) values (v4,v5,v6)
...
into your_table(c1,c2,c3) values (vN,vO,vP)
select * from dual;
批量插入/ SQL集合:
FORALL i IN your_collection.first .. your_collection.last
INSERT INTO your_table(c1,c2,c3)
VALUES(your_collection(i).v1
, your_collection(i).v2
, your_collection(i).v3);
或
FORALL i IN INDICES OF your_collection
INSERT INTO your_table(c1,c2,c3)
VALUES(your_collection(i).v1
, your_collection(i).v2
, your_collection(i).v3);
或使用綁定陣列批量插入:
BEGIN
FORALL i IN :lower .. :upper
INSERT INTO your_table(c1,c2,c3)
VALUES(:v1(i), :v2(i), :v3(i));
END;
我懷疑提議的「多記錄插入」能否提供足夠的性能。該命令的大小可能爲1 MB(或100萬個字符)。只是發送和解析這樣的命令將需要一些時間。您很可能會額外努力發送CLOB等命令。 –
我想用PreparedStatement
和批量插入是你最好的選擇。 PreparedStatement的好處在於,sql被緩存在RDBMS服務器上,批量插入可以以批處理的形式完成。
喜歡的東西:
private void doInsert(Connection conn, List<Data> data){
String sql = "INSERT INTO T (A,B,C) VALUES (?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
int count = 0;
for(Data d : data) {
count++;
ps.setString(1, data.getA());
ps.setString(2, data.getB());
ps.setString(3, data.getC());
ps.addBatch();
if (count%1000 == 0) {
ps.executeBatch();
}
}
ps.executeBatch();
ps.close();
}
這真的是最好的答案,因爲它直接處理java'List',如何以可管理的批次分解它(並不總是一個單一的兆字節批是最好的),以及如何以標準jdbc方式處理批處理。 – YoYo
無論哪種方式是好的,按我的知識,我會選擇2 MyBatis的一批去。 – PKR
您應該爲每種方法確實設置測試用例,並查看數據,硬件,網絡等的性能。 – Boneist
jdbc使用標準SQL直接支持批插入。雖然批處理實現不能保證被所有數據庫支持,但它受Oracle jdbc驅動程序支持,而Oracle PLSQL僅*受Oracle支持。另外,對於存儲過程,您將具有處理數組傳遞的額外複雜性。 – YoYo