k collect INSERT的效果
以上可以看到拼接SQL的写法不管是对比 setExecuteBatch 还是 executeBatch都要满几百倍。
拼接15000条INSERT语句到一个Pl/SQL block中的慢主要体现在:
他是一个太长的PL/SQL block,在第一次 Parse解析时Oracle 使用PL/SQL engine引擎要扫描整个block,从上面的tkprof结果可以看到光parse就消耗了179秒,即便不用setExecuteBatch 还是 executeBatch仅使用最普通的batch size=1的循环SQL也要比这个拼接SQL块。
它的执行需要在Pl/SQL引擎和SQL引擎之间不断切换,所以Execute也非常慢
它要分配60000个绑定变量,这对于PGA的压力太大了,很可能导致SWAP
由于变量和SQL过长,会引起一些莫名得小概率发生的BUG
实际上JDBC 原生态的 setExecuteBatch 、 executeBatch都是为了减少 client-server之间的交互。
setExecuteBatch 是等待可执行的SQL达到一定数目后,一次性提交给Oracle,一般推荐的Batch Size是20~50,我简单测试了不同batch size在本例中的情况:
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 1 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 4990 miliseconds.
batch size= 1 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 3778 miliseconds.
成功构建 (总时间: 9 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 10 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 829 miliseconds.
batch size= 10 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 474 miliseconds.
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 20 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 694 miliseconds.
batch size= 20 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 366 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 30 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 516 miliseconds.
batch size= 30 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 204 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 40 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 481 miliseconds.
batch size= 40 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 188 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 50 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 456 miliseconds.
batch size= 50 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 171 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 100 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 450 miliseconds.
batch size= 100 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 123 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 200 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 402 miliseconds.
batch size= 200 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 92 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 500 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 386 miliseconds.
batch size= 500 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 95 miliseconds.
成功构建 (总时间: 1 秒)
alter system flush shared_pool 已刷新共享池,避免SQL游标缓存 影响第二次测试
batch size= 1000 常规循环 15000 次 INSERT SQL 第一次运行的耗时 Elapsed time was 369 miliseconds.
batch size= 1000 常规循环 15000 次 INSERT SQL 第二次运行的耗时 Elapsed time was 87 miliseconds.
成功构建 (总时间: 1 秒)www.2cto.com
可以看到上述例子中200~500的Execute batch size获得的性能较好。
PreparedStatement+addBatch()+executeBatch()的方式很像PL/SQL中的bulk collect处理,将变量置入batch array中,执行时将array中的数据一次插入到表中,即解析一次、执行一次,虽然对PGA会有一些少量压力,但是从上例中也能看到,获得了最快的速度。
综上所述对于
Java Jdbc减少交互提升批量处理性能,最好的办法是 尽可能多用PreparedStatement s