批处理写入以及动态与参数化SQL,数据库的性能如何?
批處理寫入是最有效的數(shù)據(jù)庫優(yōu)化之一。 批處理寫入受大多數(shù)現(xiàn)代數(shù)據(jù)庫和JDBC標準的一部分支持,并且受大多數(shù)JPA提供程序支持。
普通數(shù)據(jù)庫訪問包括在單獨的數(shù)據(jù)庫/網(wǎng)絡訪問中將每個DML(插入,更新,刪除)語句發(fā)送到數(shù)據(jù)庫。 每個數(shù)據(jù)庫訪問都有一定的開銷,并且數(shù)據(jù)庫必須獨立處理每個語句。 批處理寫入有兩種形式,動態(tài)的和參數(shù)化的。 參數(shù)化是最常見的方法,通常可以帶來最大的好處,因為動態(tài)可能存在解析問題。
要了解批處理編寫,您必須首先了解參數(shù)化的SQL。 SQL執(zhí)行由兩部分組成,即解析和執(zhí)行。 解析包括將字符串SQL表示形式轉(zhuǎn)換為數(shù)據(jù)庫表示形式。 執(zhí)行包括在數(shù)據(jù)庫上執(zhí)行已解析的SQL。 數(shù)據(jù)庫和JDBC支持綁定參數(shù),因此SQL(數(shù)據(jù))的參數(shù)不必嵌入到SQL中。 這避免了將數(shù)據(jù)轉(zhuǎn)換為文本的成本,并允許重復執(zhí)行同一SQL語句并執(zhí)行多次。 這允許單個解析和多個執(zhí)行,也稱為“參數(shù)化SQL”。 大多數(shù)JDBC DataSource實現(xiàn)和JPA提供程序都支持參數(shù)化的SQL和語句緩存,這可以有效避免在運行的應用程序中進行解析。
動態(tài)SQL示例
INSERT INTO EMPLOYEE (ID, NAME) VALUES (34567, "Bob Smith")參數(shù)化的SQL示例
INSERT INTO EMPLOYEE (ID, NAME) VALUES (?, ?)參數(shù)化批處理編寫涉及執(zhí)行單個DML語句,但是具有用于多個同質(zhì)語句的一組綁定參數(shù),而不是用于單個語句的綁定參數(shù)。 這有效地允許數(shù)據(jù)庫和網(wǎng)絡將大批同質(zhì)的插入,更新或刪除作為單個操作而不是n個操作來處??理。 數(shù)據(jù)庫僅需要執(zhí)行最少的工作,因為只有一條語句,因此最多只有一個解析。 它也與語句緩存兼容,因此根本不需要進行語句解析。 限制是所有語句的SQL必須相同。 因此,說插入1,000個Orders確實非常有用,因為每個Order的插入SQL都是相同的,只是bind參數(shù)不同。 但這對于插入1個訂單或插入1個訂單,1個OrderLine和1個客戶沒有幫助。 同樣,所有語句必須是同一數(shù)據(jù)庫事務的一部分。
動態(tài)批處理編寫包括將一堆異構動態(tài)SQL語句鏈接到一個塊中,然后通過單個數(shù)據(jù)庫/網(wǎng)絡訪問將整個塊發(fā)送到數(shù)據(jù)庫。 這是有利的,因為只有一個網(wǎng)絡訪問權限,因此,如果數(shù)據(jù)庫是遠程的或通過慢速的網(wǎng)絡訪問,則可能會有很大的不同。 缺點是不允許參數(shù)綁定,并且數(shù)據(jù)庫必須在接收到此龐大的SQL塊時對其進行解析。 在某些情況下,解析成本可能超過網(wǎng)絡收益。 另外,動態(tài)SQL與語句緩存不兼容,因為每個SQL都不相同。
JDBC通過其Statement和PrepareStatement批處理API(從JDBC 2.0開始,很早以前就是JDK 1.2)標準化了批處理寫入。 JDBC批處理API需要不同的JDBC代碼,因此,如果您使用的是原始JDBC,則需要重寫代碼以在批處理和非批處理API之間切換。 現(xiàn)在,大多數(shù)JDBC驅(qū)動程序都支持這些API,但是有些驅(qū)動程序?qū)嶋H上并不模擬DML批量發(fā)送DML到數(shù)據(jù)庫。 那么,如何知道您是否真的正在批量編寫? 唯一真正的方法是對其進行測試,并衡量性能差異。
JPA規(guī)范沒有標準化批寫配置,但是大多數(shù)JPA提供程序都支持它。 通常,通過持久性單元屬性在JPA中啟用批處理寫入,因此打開或關閉它是一個簡單的配置問題,并且不需要更改編碼。 一些JPA提供程序在使用開放式鎖定時可能不支持批處理寫入,并且可能不對SQL進行重新排序以使其能夠進行批處理,因此即使啟用了批處理寫入,您仍可能無法進行批處理寫入。 始終在啟用和禁用批寫的情況下測試您的應用程序,并測量差異以確保其實際運行。
EclipseLink支持參數(shù)化和動態(tài)批處理編寫(自EclipseLink 1.0起)。 在EclipseLink中,通過"eclipselink.jdbc.batch-writing"持久性單元屬性啟用批處理寫入。 EclipseLink提供了三個選項: "JDBC" , "Buffered"和"Oracle-JDBC" 。 應始終使用"JDBC"選項。
"Buffered"用于不支持批量寫入的JDBC驅(qū)動程序,并將動態(tài)SQL語句鏈接到單個塊本身中。 "Buffered"不支持參數(shù)化的SQL,因此不建議使用。
"Oracle-JDBC"使用早于JDBC標準API的Oracle數(shù)據(jù)庫JDBC API,現(xiàn)在已過時。 在EclipseLink 2.5之前,此選項允許在使用開放式鎖定時進行批處理寫入,但是現(xiàn)在常規(guī)的"JDBC"選項支持開放式鎖定。
EclipseLink 2.5支持在所有(兼容)數(shù)據(jù)庫平臺上進行樂觀鎖定的批處理寫入,而以前僅在選定的數(shù)據(jù)庫平臺上才支持。 EclipseLink 2.5還提供了一個"eclipselink.jdbc.batch-writing"查詢提示,以禁止無法寫入的本機查詢(例如DDL或某些數(shù)據(jù)庫平臺上的存儲過程)的批量寫入。
EclipseLink通過"eclipselink.jdbc.bind-parameters"和"eclipselink.jdbc.cache-statements"持久單元屬性來支持參數(shù)化SQL。 但是,通常不需要設置這些參數(shù),因為參數(shù)綁定是默認設置,因此您只需將屬性設置為禁用綁定即可。 默認情況下,語句緩存未啟用,如果使用EclipseLink的連接池,則僅與EclipseLink相關;如果使用的是JDBC或Java EE DataSource,則必須在DataSource配置中配置語句緩存。
在EclipseLink中啟用批量寫入時,默認情況下它是參數(shù)化的批量寫入。 要啟用動態(tài)批處理寫入,必須禁用參數(shù)綁定。 這與啟用緩沖批寫入相同。
支持批處理寫入并不是很難,大多數(shù)JPA提供程序都支持這一點,對SQL進行排序以使其可以進行批處理是困難的部分。 在提交或刷新操作期間,EclipseLink會自動按表對SQL進行分組,以確保可以批處理同類的SQL語句(同時仍保持引用完整性約束并避免死鎖)。 大多數(shù)JPA提供程序都不這樣做,因此即使它們支持批處理寫入,SQL的很多時間也無法從批處理中受益。
要在EclipseLink中啟用批處理寫入,請將以下內(nèi)容添加到持久性單元屬性;
"eclipselink.jdbc.batch-writing"="JDBC"您還可以使用"eclipselink.jdbc.batch-writing.size"持久性單元屬性來配置批處理大小。 默認大小為100。
"eclipselink.jdbc.batch-writing.size"="1000"批處理非常依賴數(shù)據(jù)庫,并且依賴JDBC驅(qū)動程序。 因此,我對與哪些數(shù)據(jù)庫,它使用的驅(qū)動程序以及好處有興趣。 我進行了兩次測試,一個進行了50次插入操作,一個進行了100次更新操作(使用樂觀鎖定)。 我嘗試了所有批處理寫入選項,以及不使用任何批處理。
請注意,這不是數(shù)據(jù)庫基準,我不是在相互比較數(shù)據(jù)庫,而只是對自己進行比較 。
每個數(shù)據(jù)庫都在不同的硬件上運行,有些是本地的,有些是跨網(wǎng)絡的,因此不要將一個數(shù)據(jù)庫與另一個數(shù)據(jù)庫進行比較。 感興趣的數(shù)據(jù)是使批寫入相對于不使用批寫入所帶來的百分比收益。 對于插入測試,我還測量了使用參數(shù)化SQL與動態(tài)SQL以及不使用語句緩存的參數(shù)化SQL之間的差異。 結(jié)果是在10秒內(nèi)處理的事務數(shù)(運行5次,并平均),因此,較大的數(shù)目是更好的結(jié)果。
驅(qū)動程序:MySQL-AB JDBC驅(qū)動程序版本:mysql-connector-java-5.1.22
插入測試
| 參數(shù)化SQL,無批處理 | 483 | 0% |
| 動態(tài)SQL,無批次 | 499 | 3% |
| 參數(shù)化的SQL,無語句緩存 | 478 | -1% |
| 動態(tài)SQL,批處理 | 499 | 3% |
| 參數(shù)化SQL,批處理 | 509 | 5% |
更新測試
| 參數(shù)化SQL | 245 | 0% |
| 動態(tài)SQL,批處理 | 244 | 0% |
| 參數(shù)化SQL,批處理 | 248 | 1% |
因此,結(jié)果似乎表明批處理寫入沒有任何影響(5%在方差之內(nèi))。 這的真正含義是,MySQL JDBC驅(qū)動程序?qū)嶋H上并不使用批處理,它只是模擬JDBC批處理API,并在其下逐個執(zhí)行語句。
盡管MySQL確實具有批處理支持,但它只需要不同的SQL。 MySQL JDBC驅(qū)動程序確實支持此功能,但是需要設置rewriteBatchedStatements=true JDBC連接屬性。 可以通過修改您的連接URL輕松地進行設置,例如;
jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=trueMySQL:rewriteBatchedStatements = true
插入測試
| 參數(shù)化SQL,無批處理 | 504 | 0% |
| 動態(tài)SQL,無批次 | 508 | 0% |
| 參數(shù)化的SQL,無語句緩存 | 483 | -4% |
| 動態(tài)SQL,批處理 | 1292 | 156% |
| 參數(shù)化SQL,批處理 | 2181 | 332% |
更新測試
| 參數(shù)化SQL | 250 | 0% |
| 動態(tài)SQL,批處理 | 669 | 167% |
| 參數(shù)化SQL,批處理 | 699 | 179% |
因此,如果配置正確(似乎JDBC驅(qū)動程序默認不執(zhí)行此操作,我不知道),那么批處理寫入確實會在MySQL中產(chǎn)生很大的不同。 參數(shù)化批處理寫入效果最佳,插入速度快332%,更新速度快179%。 動態(tài)批處理寫入效果也很好。 有趣的是,MySQL上的動態(tài)SQL和參數(shù)化SQL之間似乎沒有什么區(qū)別(我猜想MySQL解析的速度確實更快,或者對預準備語句的優(yōu)化很少)。
PostgreSQL 8.4 JDBC4
插入測試
| 參數(shù)化SQL,無批處理 | 479 | 0% |
| 動態(tài)SQL,無批次 | 418 | -12% |
| 參數(shù)化的SQL,無語句緩存 | 428 | -10% |
| 動態(tài)SQL,緩沖 | 1127 | 135% |
| 動態(tài)SQL,批處理 | 1127 | 135% |
| 參數(shù)化SQL,批處理 | 2037 | 325% |
更新測試
| 參數(shù)化SQL | 233 | 0% |
| 動態(tài)SQL,批處理 | 395 | 69% |
| 參數(shù)化SQL,批處理 | 707 | 203% |
結(jié)果表明,批寫在PostgreSQL上有很大的不同。 參數(shù)化批處理寫入性能最佳,插入速度快325%,更新速度快203%。 動態(tài)批處理寫入效果也很好。 對于PostgreSQL,我還評估了EclipseLink的緩沖批處理寫入的性能,該性能與動態(tài)JDBC批處理寫入的性能相同,因此我假設驅(qū)動程序在做相同的事情。 參數(shù)化的SQL優(yōu)于動態(tài)SQL約10%,但不帶語句緩存的參數(shù)化SQL與動態(tài)SQL相似。
Oracle JDBC驅(qū)動程序版本:11.2.0.2.0
插入測試
| 參數(shù)化SQL,無批處理 | 548 | 0% |
| 動態(tài)SQL,無批次 | 494 | -9% |
| 參數(shù)化的SQL,無語句緩存 | 452 | -17% |
| 動態(tài)SQL,緩沖 | 383 | -30% |
| 動態(tài)SQL,批處理 | 489 | -10% |
| 參數(shù)化SQL,批處理 | 3308 | 503% |
更新測試
| 參數(shù)化SQL | 282 | 0% |
| 動態(tài)SQL,批處理 | 258 | -8% |
| 參數(shù)化SQL,批處理 | 1672 | 492% |
結(jié)果表明,參數(shù)化批處理寫入對Oracle產(chǎn)生了很大的影響,插入速度快503%,更新速度快492%。 動態(tài)批處理寫入沒有任何好處,這是因為Oracle的JDBC驅(qū)動程序僅模擬動態(tài)批處理并逐個執(zhí)行語句,因此它具有與動態(tài)SQL相同的性能。 緩沖批寫入實際上比根本不批處理具有更差的性能。 這是因為巨大的動態(tài)SQL塊的解析成本,這在不同的配置中可能會有所不同,如果數(shù)據(jù)庫是遠程的或跨慢速的網(wǎng)絡,則我會看到這樣做的好處。
帶有語句緩存的參數(shù)化SQL比動態(tài)SQL提供約10%的收益,并指出,要從參數(shù)化中受益,您需要使用語句緩存,否則性能可能會比動態(tài)SQL差。 粗略地講,參數(shù)化SQL還有其他好處,因為它從服務器中刪除了CPU處理,這在單線程情況下可能無濟于事,但在數(shù)據(jù)庫是瓶頸的多線程情況下,可能會產(chǎn)生很大的不同。
(本地)
插入測試
| 參數(shù)化SQL,無批處理 | 3027 | 0% |
| 動態(tài)SQL,無批次 | 24 | -99% |
| 參數(shù)化的SQL,無語句緩存 | 50 | -98% |
| 動態(tài)SQL,批處理 | 24 | -99% |
| 參數(shù)化SQL,批處理 | 3252 | 7% |
更新測試
| 參數(shù)化SQL | 1437 | 0% |
| 動態(tài)SQL,批處理 | 6 | -99% |
| 參數(shù)化SQL,批處理 | 2172 | 51% |
結(jié)果表明,參數(shù)化批處理寫入對Derby有所不同,插入速度快7%,更新速度快51%。 由于我的數(shù)據(jù)庫是本地數(shù)據(jù)庫,因此結(jié)果差異不如其他數(shù)據(jù)庫那么大。 對于網(wǎng)絡數(shù)據(jù)庫,這將是一個更大的差異,但這確實表明,即使對于本地數(shù)據(jù)庫,批處理寫入也可以帶來好處,因此,這不僅僅是網(wǎng)絡優(yōu)化。 Derby真正有趣的結(jié)果是動態(tài)和非緩存語句的可怕性能。 這表明Derby具有巨大的解析成本,因此,如果您使用的是Derby,那么將帶參數(shù)的SQL與語句緩存一起使用非常重要。
用于JDBC和SQLJ的IBM數(shù)據(jù)服務器驅(qū)動程序版本:4.0.100
結(jié)果基本上與Oracle類似,因為參數(shù)化的批處理編寫具有很大的性能優(yōu)勢。 動態(tài)批處理寫入的性能較差,因此無法使用參數(shù)化SQL進行批處理,而動態(tài)SQL和未使用語句緩存的參數(shù)化SQL會導致性能降低。
Microsoft SQL Server JDBC驅(qū)動程序2.0版本:2.0.1803.100
結(jié)果類似于PostgreSQL,顯示參數(shù)化和動態(tài)批處理編寫均提供了顯著的好處。 參數(shù)化批處理編寫性能最好,參數(shù)化SQL優(yōu)于動態(tài)SQL,并且沒有語句緩存。
**更新**
有人要求我也測試H2和HSQL,所以這里是結(jié)果。
(本地)
插入測試
| 參數(shù)化SQL,無批處理 | 4757 | 0% |
| 動態(tài)SQL,無批次 | 3210 | -32% |
| 參數(shù)化的SQL,無語句緩存 | 4757 | 0% |
| 動態(tài)SQL,緩沖 | 1935年 | -59% |
| 動態(tài)SQL,批處理 | 3293 | -30% |
| 參數(shù)化SQL,批處理 | 5753 | 20% |
結(jié)果表明,通過參數(shù)化批處理寫入,H2的執(zhí)行速度提高了20%。 H2是一個內(nèi)存數(shù)據(jù)庫(由持久日志文件支持),因此預期不會受益于不涉及任何網(wǎng)絡的情況。 動態(tài)批處理編寫和動態(tài)SQL執(zhí)行的參數(shù)化SQL更差。 有趣的是,將參數(shù)緩存與參數(shù)化SQL一起使用不會產(chǎn)生任何區(qū)別。 我的假設是H2始終在其連接中緩存準備好的語句,因此用戶不需要自己進行語句緩存。
(本地)
插入測試
| 參數(shù)化SQL,無批處理 | 7319 | 0% |
| 動態(tài)SQL,無批次 | 5054 | -30% |
| 參數(shù)化的SQL,無語句緩存 | 6776 | -7% |
| 動態(tài)SQL,批處理 | 5500 | -24% |
| 參數(shù)化SQL,批處理 | 9176 | 25% |
結(jié)果表明,通過參數(shù)化批處理編寫,HSQL的執(zhí)行速度提高了25%。 HSQL是一個內(nèi)存數(shù)據(jù)庫(由持久日志文件支持),因此期望它不會像沒有網(wǎng)絡一樣受益。 動態(tài)批處理編寫和動態(tài)SQL執(zhí)行的參數(shù)化SQL更差。
翻譯自: https://www.javacodegeeks.com/2013/09/batch-writing-and-dynamic-vs-parametrized-sql-how-well-does-your-database-perform.html
總結(jié)
以上是生活随笔為你收集整理的批处理写入以及动态与参数化SQL,数据库的性能如何?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 田园诗派的创始人是谁(关于陶渊明的杂诗代
- 下一篇: 播放器排行榜前十名(常用的十大视频播放器