我需要使用JDBC将大量插入(即两位数百万)插入Oracle-DB.为此,我使用类似下面的类,灵感来自使用JDBC进行批量INSERTS的高效方法:
public class Inserter {
private final int batchSize;
private final Connection con; // with .setAutoCommit(false)
private final PreparedStatement ps;
private int currentSize = 0;
public Inserter(Connection con, PreparedStatement ps, int batchSize) {
this.con = con;
this.ps = ps;
this.batchSize = batchSize;
}
public void addInsert(Object[] vals) throws SQLException {
ps.clearParameters(); // should be redundant, but better safe than sorry
for (int i = 0; i < val.length; i++) {
this.ps.setObject(i + 1, vals[i]);
}
ps.addBatch();
currentSize++;
if (currentSize >= batchSize) {
ps.executeBatch();
currentSize = 0;
}
}
public void flush() {/** to flush leftovers */}
}
Run Code Online (Sandbox Code Playgroud)
虽然这种插入方式很好,但速度很慢.JDBC批处理插入性能描述了基本上如何处理MySQL的确切问题,rewriteBatchedStatements但是在Oracle上似乎不存在它在这里没有多大帮助.
为了提高性能,我还尝试将Statement切换为一个大INSERT ALL .../ INSERT APPEND ...语句,根据Oracle 11g - 插入多行的最有效方法,这使得一切都更慢.
因此,我的问题是,如果有任何方法可以优化这些插入,而不仅仅是使用addBatch()和executeBatch()?或者Inserter上面的课程中是否存在一些严重,低效的错误?任何帮助将非常感谢.
更有用的信息:
要插入的表被分区,每个分区大约有一到一千万行.
对于这样的表有一个唯一约束, unique(id1, id2, id3, id4)其中的所有列都是类型,NUMBER并且进一步由外键约束绑定到其他表中的主键.
编辑:
根据评论中的建议,我将setObject(index, val)电话转为:
setInt(index, val),setFloat(index, val),...,setNull(index, type)调用其中apprpropriate
setObject(index, val, type) 和 setNull(index, typR)
两个版本都没有显着提高性能.
此外,我尝试将数据插入到临时表中,没有任何约束,这也没有带来更好的性能.
为了进行比较,将数据导出为CSV并使用SQL*Loader将其加载导致显着的性能提升,即对于最慢的表1,每秒~4.5k => ~50k +行.
这让我相信JDBC存在的瓶颈.
1 唉,在我的特定情况下,SQL*Loader的使用不是(期望的)选项.
Ska*_*out -1
你永远不会提交该批次。如果可以在未提交查询的情况下在executeBatch之后添加提交,您将创建较大的回滚段,从而降低数据库速度。还要删除 ps.clearParameters() 因为您总是覆盖所有参数或不覆盖任何参数。最好使用专门版本的 setter 而不是 setObject
| 归档时间: |
|
| 查看次数: |
656 次 |
| 最近记录: |