优化oracle jdbc批处理插入

时间:2019-01-30 16:38:39

标签: java oracle jdbc

我需要使用JDBC在Oracle-DB中进行大量插入,即两位数百万插入。为此,我使用的是受Efficient way to do batch INSERTS with JDBC启发的以下类:

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 */}
}

虽然这种插入方式可以正常工作,但速度非常慢。 JDBC batch insert performance描述了如何从根本上解决MySQL的确切问题,因为rewriteBatchedStatements在Oracle上似乎并不存在,在这里并没有太大帮助。

为了提高性能,我还尝试根据Oracle 11g - most efficient way of inserting multiple rows将Statement切换为一个大的INSERT ALL ... / INSERT APPEND ...语句,这会使一切变得更慢。

因此,我的问题是,除了简单地使用addBatch()executeBatch()之外,还有没有其他方法可以优化这些插入内容?还是上面的Inserter类中可能存在一些严重的,效率低下的错误?任何帮助将不胜感激。


更多可能有用的信息:

  • 要插入的表已分区,每个分区大约有一到一千万行。

  • 在表上有一个唯一的约束,看起来像unique(id1, id2, id3, id4),其中所有列均为NUMBER类型,并且进一步由外键约束绑定到其他表中的主键。


编辑:

根据评论的建议,我将setObject(index, val)呼叫切换为:

  1. setInt(index, val)setFloat(index, val)...setNull(index, type)调用在适当的地方

  2. setObject(index, val, type)setNull(index, typR)

两个版本均未显着提高性能。

此外,我尝试将数据插入没有任何约束的登台表中,这也没有带来更好的性能。

相比之下,将数据导出到CSV并使用SQL * Loader加载将导致性能显着提高,例如,对于最慢的表 1 ,每秒〜4.5k =>〜50k +行。

这使我相信JDBC的瓶颈所在。

1 A,在我的特殊情况下,使用SQL * Loader并不是(期望的)选项。

1 个答案:

答案 0 :(得分:0)

您从不提交批处理。如果可能,在executeBatch之后添加提交 如果未提交查询,则将创建大型回滚段,这可能会减慢速度 关闭数据库。还要删除ps.clearParameters(),因为您始终会覆盖所有参数或不覆盖任何参数。最好使用专业版的setter代替setObject