【问题标题】:Optimize copyTable function to Oracle in Java用Java优化copyTable函数到Oracle
【发布时间】:2020-10-29 23:14:23
【问题描述】:

我喜欢将一些表复制到我的Oracle数据库中,所以我写了这个Java方法:

public static int copyTable (String cmdSelect, String cmdInsert, String sourceURL) throws SQLException {
    int rowCount = 0;

    try {
        Connection conOra = DriverManager.getConnection("jdbc:default:connection:");
        Connection conGauss = DriverManager.getConnection(sourceURL, "username", "password");

        PreparedStatement sthSel = conGauss.prepareStatement(cmdSelect);
        PreparedStatement sthIns = conOra.prepareStatement(cmdInsert);

        ResultSet rs = sthSel.executeQuery();
        ResultSetMetaData rsmd = rs.getMetaData();
        
        while ( rs.next() ) {
            for( int c = 1; c <= rsmd.getColumnCount(); c++ ) {
                sthIns.setObject(c, rs.getObject(c), rsmd.getColumnType(c), rsmd.getScale(c));
            }
            sthIns.addBatch();
            rowCount++;
            if (rowCount % 10000 == 0) {
                sthIns.executeBatch();
            }
        }
        sthIns.executeBatch();
        
        rs.close();
        sthSel.close();
        sthIns.close();
        conGauss.close();
        conOra.close();
    }
    catch (SQLException e) {
        throw e;
    }
    return rowCount;
}

我在 Oracle 中创建了函数

CREATE OR REPLACE FUNCTION copyTable(cmdSelect VARCHAR2, cmdInsert VARCHAR2, sourceURL VARCHAR2) RETURN NUMBER 
AS LANGUAGE JAVA NAME 'Gauss.copyTable(java.lang.String, java.lang.String, java.lang.String) return int';

我这样称呼它:

DECLARE
    cmdSelect VARCHAR2(1000) := 'SELECT NRID, NEID, NRNAME, NR_NAME, NBTYPE, NETYPE, GNODEBID, INVALIDTIME, OBJECTSTATUS FROM D_NR';
    cmdInsert VARCHAR2(1000) := 'INSERT INTO D_NR_COPY (NRID, NEID, NRNAME, NR_NAME, NBTYPE, NETYPE, GNODEBID, INVALIDTIME, OBJECTSTATUS) VALUES (?,?,?,?,?,?,?,?,?)';
    ret INTEGER;
BEGIN
    ret := copyTable(cmdSelect, cmdInsert, 'some URL');
    DBMS_OUTPUT.PUT_LINE ( 'ret = ' || ret );
    COMMIT;
END;

我的第一次测试运行良好,程序按预期运行。但是我有点担心性能,有些表会比较大。我对Java一无所知。

我必须为每一行循环for ( int c = 1; c &lt;= rsmd.getColumnCount(); c++ ) ,还是有更快的方法?

使用while ( rs.next() )分批读取源表而不是逐行读取是否可行且有益?

注意,普通的INSERT INTO D_NR_COPY (...) SELECT ... FROM D_NR 不起作用,因为源数据库不是 Oracle 数据库。

【问题讨论】:

  • 您不能创建指向源数据库的数据库链接吗?使用数据库链接的单个插入选择 sql 会快得多
  • @SayanMalakshinov 不,数据库链接到非 Oracle 是不可能的。您可以使用“Oracle Database Gateway for ODBC”,但是源数据库是华为 GaussDB,而我们的 Oracle 在 Redhat Linux 上运行。由于特朗普/美国的禁令,华为可能不会在 Redhat 上为其 DB 提供 ODBC 驱动程序,同样适用于 Windows。将我们的 Oracle 迁移到另一个 Linux(例如 Suse Linux)也不是一种选择。

标签: java oracle performance dynamic-sql


【解决方案1】:

JDBC 驱动程序通常获取多行。默认行数取决于驱动程序(例如,Oracles 的 JDBC 驱动程序默认为 10)。您可以通过 Statement.getFetchSize() 检查默认提取大小并通过 Statement.setFetchSize(int) 增加它。请注意,获取大小只是 JDBC 驱动程序的提示,它可能会忽略或覆盖大小。如果应该忽略设置的提取大小,我建议检查 JDBC 驱动程序的文档。

虽然理论上是可能的(取决于 JDBC 驱动程序的实现),但对 ResultSetMetaData 方法的调用不太可能触发对 DB 的额外调用。整个元数据更有可能已经在内存中。在这种情况下,这里不需要优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-20
    • 2021-02-13
    • 1970-01-01
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    相关资源
    最近更新 更多