Оптимизировать функцию copyTable до Oracle в Java - PullRequest
1 голос
/ 09 июля 2020

Мне нравится копировать некоторые таблицы в свою 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.

Нужно ли мне l oop for ( int c = 1; c <= rsmd.getColumnCount(); c++ ) для каждой строки или есть какой-то более быстрый способ сделать это?

Это возможно и полезно для чтения исходных таблиц пакетами, а не построчно с while ( rs.next() )?

Обратите внимание, простой INSERT INTO D_NR_COPY (...) SELECT ... FROM D_NR не работает, потому что исходная база данных не является базой данных Oracle.

1 Ответ

1 голос
/ 09 июля 2020

Драйвер JDB C обычно выбирает несколько строк. Количество строк по умолчанию зависит от драйвера (например, для драйвера Oracles JDB C по умолчанию установлено 10). Вы можете проверить размер выборки по умолчанию с помощью Statement.getFetchSize () и увеличить его с помощью Statement.setFetchSize (int). Обратите внимание, что размер выборки - это всего лишь подсказка для драйвера JDB C, он может игнорировать или переопределять размер. Если установленный размер выборки следует игнорировать, я рекомендую проверить do c вашего драйвера JDB C.

Хотя теоретически возможно (до реализации драйвера JDB C), это очень Маловероятно, что вызовы методов ResultSetMetaData вызывают дополнительные вызовы БД. Более вероятно, что все метаданные уже находятся в памяти. В этом случае здесь нет необходимости что-то оптимизировать.

...