1

私のアプリケーションには、データベースで更新する必要がある約 200K レコードのテーブルがあります。一致するレコードがDBに存在するかどうかをすべてのレコードをチェックしてから挿入または更新する代わりに、DB内の一致するすべてのレコードを削除して挿入する方が速いと思いました。Spring JDBC フレームワークを使用しています。削除するには Jdbctemplate の batchUpdate メソッドを ParameterizedPreparedStatementSetter と共に使用し、挿入には SimplJdbcInsert を使用しています。挿入は正常に機能しますが、バッチ削除のパフォーマンスは非常に遅くなります。DBのレコードを削除して挿入するために他にどのようなアプローチをとるべきかはよくわかりません。どんな提案でも非常に役に立ちます。SQL Server 2008 R2 を使用しています

ParameterizedPreparedStatementSetter<Order> vSetter = 
            new ParameterizedPreparedStatementSetter<Order>() {
                @Override
                public void setValues(PreparedStatement ps,
                        Order order) throws SQLException {
                    ps.setInt(1, order.getOrderNum());
                }
    };

getJdbcTemplate().batchUpdate("DELETE FROM Order WHERE OrderNum = ?",
            aDemandOrders,
            50000,
            vSetter);
4

1 に答える 1

1

パフォーマンスが低下する理由は、DB がステートメントのバッチを受け取りますが、それでも 1 つずつ実行するためです。

別の方法として、節を使用しin ()てステートメントを手動でバッチ処理し、DB が各バッチ サイズで 1 つのステートメントを実行できるようにすることもできます。

ただし、クエリ キャッシュの利点を引き続き得るには、すべてを 1 つのin ()句で単純に送信するのではなく、適切にバッチ処理する必要があります。

private static final int MIN = 1;
private static final int SML = 4;
private static final int MED = 11;
private static final int MAX = 51;
private static final String DEL_ORDERS_QRY
    = "DELETE FROM Order WHERE OrderNum in (:orders)";

public void deleteOrders(Collection<Integer> origIds) {
    int done = getJdbcTemplate().execute((Connection con) -> {
        // Reuse this query, `:orders` is a placeholder for the in-clause.

        LinkedList<Integer> ids = new LinkedList<>(origIds);
        int remainder = ids.size();
        int updated = 0;

        while (remainder > 0) {
            // identify the batch size for this execution.
            int batchSize;
            if (remainder >= MAX) {
                batchSize = MAX;
            } else if (remainder >= MED) {
                batchSize = MED;
            } else if (remainder >= SML) {
                batchSize = SML;
            } else {
                batchSize = MIN;
            }
            remainder -= batchSize;

            // Build the in-clause parameters.
            StringBuilder inClause = new StringBuilder(batchSize * 2);
            for (int i = 0; i < batchSize; i++) {
                if (i > 0) {
                    inClause.append(',');
                }
                inClause.append('?');
            }

            try (PreparedStatement ps = con.prepareStatement(
                    DEL_ORDERS_QRY.replace(":orders", inClause.toString()))) {
                for (int i = 0; i < batchSize; i++) {
                    ps.setInt(i + 1, ids.pop());
                }
                updated += ps.executeUpdate();
            } catch (SQLException ex) {
                log.error("Couldn't execute batch", ex);
                throw new RuntimeException(ex.getMessage(), ex);
            }
        }
        return updated;
    });
}
于 2016-01-20T02:35:11.667 に答える