2011-07-06 71 views
4

我有一個應用程序,其中"persisting to database"消耗整個應用程序流量的85%時間。使用ORM的多線程插入?

我想使用多個線程來做插入,因爲插入在這裏大都是獨立的。有沒有什麼辦法可以使用任何JPA實現來實現多線程插入?還是值得從多角度插入,從提高性能角度?

注意:一次運行中的插入記錄範圍爲10K到100K記錄。此外,性能也非常關鍵。

謝謝。

+0

你能否提供一些細節?像正在使用的數據庫,你的代碼片段(方法)。看起來有點奇怪,這可能會影響你的應用程序。 – woliveirajr

+0

您可能需要的不僅僅是應用程序重新設計,以獲得您正在尋求的效率。如果您的底層數據庫表的設計方式不支持多個插入,那麼世界上所有的應用程序優化都無濟於事。例如,在插入過程中,您能否避免桌上的索引鎖? – Perception

+0

@woliveirajr,@Perception。 [This](http://stackoverflow.com/questions/6514117/jpa-persistence-using-multiple-threads)就是用例。使用的數據庫是Oracle和eclipselink作爲ORM提供程序。 – nobody

回答

3

數據庫多線程插入語句將沒有真正執行任何更快因爲數據庫表需要插入鎖。所以你的線程將在它完成之前等待它,並在下一個可以插入之前解鎖表 - 這實際上不會使它成爲多線程而不是單線程。如果你在哪裏做,它會很可能會減慢它的速度

如果你插入你應該考慮使用任何批量插入語句BULK INSERT命令原產於您使用的數據庫10K-100K的記錄。最快的方法是本地批量插入命令,但它會要求您不要使用JPA,並直接使用JDBC調用來插入要使用批量命令的插入。

如果你不想使用本地批量命令,我推薦使用Spring的JDBCTemplate,它具有模板批量插入命令。它速度非常快,我用它在一個高交易系統上每30秒批量插入一個10k-20k的實體,我對這個性能感到非常滿意。

最後,確保您的數據庫表使用正確的索引,鍵和選項進行了優化。由於你的數據庫是瓶頸,這應該是你首先提高性能的地方之一。

+0

哪些數據庫將表格鎖定爲插入?對於甲骨文來說這不是真的,我猜想對於大多數其他數據庫來說也是如此。 –

1

當你這樣做時,你是否定期沖洗你的會話?如果沒有的話,你可能會遇到與數據庫無關的令人討厭的減速。一般情況下,您希望通過在會話中定期調用flush()然後clear()(假設您使用的是JPA的某種變體)來「批量」插入。

1

這個article有許多提示用JPA提高批處理寫入性能。我會引用兩個應該給你最佳結果的快速參考。

優化#6 - 序列 預分配

我們優化了應用程序的 第一部分,從MySQL數據庫中讀取 。第二個 的一部分是優化Oracle的寫入到 。

與寫作 過程中最大的問題是,ID生成是 使用1分配大小這 意味着,每插入會有 是更新和選擇在未來 序列號。這是一個主要的問題 ,因爲它實際上使數據庫訪問量增加了一倍。通過 默認JPA使用50的TABLE分配和SEQUENCE Id 代的預分配大小 ,IDENTITY Id的 代的1分配(從不使用IDENTITY ID生成的很好的理由)使用了1的預分配大小 。但 經常應用 不必要的偏執狂 他們的ID值孔和 預allocaiton值設置爲1。通過改變 預分配的大小從1到500, 我們減少了約1000數據庫訪問 每頁。

優化#8 - 批量寫入

許多 數據庫提供了一個優化的是 允許 一批寫操作來作爲一個單一的數據庫 接入來執行。有參數化和動態批處理書寫。對於 參數化的批量寫入單個 參數化的SQL語句可以是 執行一批參數 值而不是一組 參數值。這是非常優化的 ,因爲SQL只需要執行 一次,並且所有數據都可以是 最優地傳遞到數據庫。

動態批量寫入要求被分批 成一個大的語句,併發送 到數據庫一次全部動態 (非參數化)SQL。 數據庫然後需要處理這個 巨大的字符串並執行每個 語句。這就要求數據庫 做了很多工作,解析了 語句,所以並不總是最優的。它 確實減少了數據庫訪問,所以如果數據庫是 遠程連接或應用程序連接不好, 可以導致一個改進。

總的來說,參數化批量書寫 是最優化的,而在Oracle上它提供了巨大的好處,其中 動態不是。 JDBC定義API 批量寫作,但並不是所有的JDBC 驅動程序支持它,有些支持 API,但隨後執行該語句 一個接一個,所以測試 您的數據庫支持 優化使用它之前,它是重要的。在 中使用持久性單元屬性 「eclipselink.jdbc.batch-writing」=「JDBC」啓用EclipseLink批處理寫入 。

使用 批量寫入的另一個重要方面是,你必須有 相同的SQL(DML實際上)聲明 正在分組的時尚 單個事務執行。一些JPA 供應商不會訂購他們的DML,因此 您可以結束 之間的兩個語句,如訂單 插入和訂單行插入, 使批處理寫入無效。 幸運的EclipseLink訂單和 組其DML,所以批量 寫入的使用減少了對數據庫的訪問 從500順序插入和5000 順序線插入到55(默認 批量大小爲100)。我們可以使用 「eclipselink.jdbc.batch-writing.size」, 增加批量大小 ,因此將批量大小增加到1000 可將數據庫訪問量減少到每 頁面的6個。

+0

感謝您的信息。這非常有用。 – nobody

2

數據庫多線程插入語句將沒有真正執行任何更快 因爲在大多數的數據庫表中需要插入鎖。所以你的線程 只是等待它之前完成和解鎖表在下一個可以 插入之前 - 這真的不會使它更多的多線程比單個線程。如果 你在哪裏做,它很可能會減慢速度。

你是說同時插入不同數據庫連接在同一個表上需要獨佔鎖才能完成?我在Oracle上測試了這一點,但我並未發現這種情況。你真的有測試用例來備份你在這裏寫的內容嗎?

無論如何,批量插入當然比一次插入要快得多。