Получение ExecuteBatch для выполнения быстрее - PullRequest
4 голосов
/ 17 февраля 2012

Я пытаюсь прочитать таблицу с сервера Sybase, обработать строки и вывести результаты в другую таблицу.(Ниже мой код)

Код извлекает таблицу довольно быстро и обрабатывает одинаково быстро (добраться до той части, куда она отправляет в течение 30 секунд).Но когда я запускаю execute batch, он сидит там за 20 минут до финиша (к примеру, у меня есть таблица, которую я тестирую с 8400 строками).

Есть ли более эффективный способ сделать это?Я подхожу к тому, как я могу получать или отправлять запросы (я могу создать новую таблицу, обновить таблицу и т. Д.) - я просто не знаю, почему это так медленно (я уверен, что данные <1МБ, и я уверен, что SQL-серверу не понадобится 20 минут для анализа 8400 строк).Любые идеи? </p>

Примечание: причина, по которой это действительно плохо для меня, заключается в том, что я должен проанализировать таблицу с строками 1,2 ММ (эта таблица, с которой я сейчас работаю, является тестовой таблицей с 8400 строками)1007 *

    Connection conn = DriverManager.getConnection(conString, user, pass);


    String sql = "SELECT id,dateid,attr from user.fromtable";
    Statement st = conn.createStatement();
    ResultSet rs = st.executeQuery(sql);

    String sqlOut = "INSERT INTO user.mytabletest (id,attr,date,estEndtime) values (?,?,?,?)";
    PreparedStatement ps = conn.prepareStatement(sqlOut);

    int i=1;

    while(rs.next())
    {
        int date = rs.getInt("dateid");
        String attr = rs.getString("attr");
        String id = rs.getString("id");

        Time tt = getTime(date,attr);
        Timestamp ts = new Timestamp(tt.getTime());

        ps.setString(1, id);
        ps.setString(2, attr);
        ps.setInt(3, date);
        ps.setTimestamp(4, ts);
        ps.addBatch();

        if(i % 10000 == 0)
        {
            System.out.println(i);
            ps.executeBatch();
            conn.commit();
            ps.clearBatch();                
        }

        i++;
    }
    System.out.println("sending "+(new Date()));
    int[] results = ps.executeBatch();
    System.out.println("committing "+(new Date()));
    conn.commit();
    System.out.println("done "+(new Date()));

Ответы [ 4 ]

9 голосов
/ 18 декабря 2012

Для эффективной работы с пакетами необходимо отключить параметр AutoCommit и включить его после выполнения пакета (или, альтернативно, использовать метод connection.commit ())

connection.setAutoCommit(false);
while(rs.next())
    {
     .....
     ps.addBatch();     
    }
int[] results = ps.executeBatch();
connection.setAutoCommit(true);
5 голосов
/ 29 мая 2012

У меня была такая же проблема, я наконец-то понял ее, хотя нигде не смог найти правильного объяснения.

Ответ таков: для простых некондиционных вставок .executeBatch() не следует использовать.В пакетном режиме выполняется множество отдельных операторов «вставка в таблицу х ...», и поэтому он работает медленно.Однако, если операторы вставки были более сложными, возможно, с условиями, которые по-разному влияют на каждую строку, то для этого могут потребоваться отдельные операторы вставки, и пакетное выполнение будет действительно полезным.

В качестве примера того, что работает, попробуйте следующее, которое создает один оператор вставки в качестве PreparedStatement (но такой же концепции, как для объекта Statement) и решает проблему медленной работы:

public boolean addSetOfRecords(String tableName, Set<MyObject> objects) {
    StringBuffer sql = new StringBuffer("INSERT INTO " + tableName + " VALUES (?,?,?,?)");
    for(int i=1;i<objects.size();i++) {
        sql.append(",(?,?,?,?)");
    }
    try {
        PreparedStatement p = db.getConnection().prepareStatement(sql.toString());
        int i = 1;
        for(MyObject obj : objects) {
            p.setString(i++, obj.getValue());
            p.setString(i++, obj.getType());
            p.setString(i++, obj.getId());
            p.setDate(i++, new Date(obj.getRecordDate().getTime()));
        }
        p.execute();
        p.close();
        return true;
    } catch (SQLException e) {
        e.printStackTrace();
        return false;
    }
}
4 голосов
/ 17 ноября 2017

Добавьте ? RewriteBatchedStatements = true в конец вашего URL JDBC. Это даст вам серьезное улучшение производительности. Обратите внимание, что это относится к MySql, не будет иметь никакого эффекта с другими драйверами JDBC.

Например: jdbc: mysql: // сервер: 3306 / db_name? RewriteBatchedStatements = true

Это улучшило мою производительность более чем в 15 раз

0 голосов
/ 26 января 2018

Существует коммерческое решение от Progress DataDirect для преобразования пакетов JDBC в собственный протокол массовой загрузки базы данных для значительного повышения производительности. Он очень популярен в SQL Server, поскольку не требует BCP. Я нанят этим поставщиком и написал в блоге , как массово вставлять пакеты JDBC .

...