2015-11-30 36 views
5

我有父/子單向關係。當我審視我看到有每個子行單獨插入查詢日誌,相當於我們說:在JPA中插入多行的最有效方法

insert into childTable(col1, col2) values(val1, val2); 
insert into childTable(col1, col2) values(val3, val4); 

那豈不是更有效地插入一個查詢的所有行?一些沿線:

insert into childTable(col1, col2) values(val1, val2), (val3, val4) 

有沒有辦法強制JPA生成多行插入,而不是單行插入?

編輯:我目前正在使用級聯插入,所以我插入父級,並自動生成插入兒童。我寧願繼續使用該方法,而不是讓我們手動創建一個巨大的SQL查詢,因爲我認爲級聯插入可以產生更清晰的代碼。

我已經定期刷新會話以控制L1緩存的大小,因此內存不足並不是問題。

回答

2

在單個查詢中插入所有行實際上效率較低。

首先,一些觀察:

  1. 的數據量從客戶端傳遞到服務器是一樣的無論是作爲一個或多個插入語句,其中「數據量」意味着你的實際值存儲。
  2. Hibernate支持批量處理請求,因此客戶端和服務器之間的往返次數可以與一個或多個插入語句大致相同。

在封面之下,Hibernate使用代表您執行的每個查詢的PreparedStatement,並且這些被緩存和重用。 MySQL緩存「編譯」SQL語句。在不深入細節的情況下,底層技術經過高度優化,可以多次運行相對較少的查詢。

如果您將插入作爲單個語句執行,那麼每次插入值的數量不同時,必須編譯和緩存新的SQL(可能推送來自緩存的另一個查詢),這會增加開銷。當您每次只使用相同的SQL時,可避免此開銷。

由於很多原因,你必須在SQL中使用綁定變量,而Hibernate會自動爲你做這件事。如果您執行一些自定義查詢來測試一次性插入方法,那麼您絕對也應該使用綁定變量。

另一個考慮因素是如何生成標識符。如果它是通過數據庫中的標識列,那麼Hibernate需要收回每列的ID,這通常只有在創建一行時纔有可能。出於這個原因,基於序列的標識符生成器對於效率是首選,客戶端緩存序列值。

我剛剛注意到你的編輯:我的經驗是,Hibernate在處理插入父子數據時會做「額外」更新。儘管我只有多對一的關係,但通過將映射更改爲具有「連接」表(就像您將看到的多對多關係),我設法獲得了「純粹」插入。在我的情況下,對三個表執行更多的插入操作比對兩個表中的更少的插入操作和更新要快得多。如果你關心性能,你肯定應該計劃一段時間來調整Hibernate配置。

+0

這是非常有幫助的。我非常肯定多行插入並不會更好,但我想通過遍歷底層B樹只可以得到一些改進。我使用自動增量主鍵,但會考慮使用序列。 – ventsyv

+1

@ventsyv&Rob我知道我遲到討論,但檢查[this](http://stackoverflow.com/a/1793209/1398531)out –

+0

@AbhishekBhatia你鏈接到的問題是談論多值插入vs 。單獨的單值插入。這個問題是在支持批量插入的休眠環境中。該批處理將向服務器的一次往返中插入多行,併爲所有單獨的插入重新使用解析的語句。如果這種區分不清楚,我建議你提出一個新問題:引用這兩個問題,並問爲什麼答案看起來矛盾。 – Rob

相關問題