web-dev-qa-db-ja.com

JavaからOracleへの一括挿入

多くの小さな行をOracleにすばやく挿入する必要があります。 (5フィールド)。

MySQLでは、挿入を100のグループに分割し、100の挿入のグループごとに1つの挿入ステートメントを使用します。

しかし、Oracleの場合、ユーザーからのフィードバックは、大量挿入(1000〜30000のどこか)が遅すぎるというものです。

JavaからOracleへのプログラムによる挿入を高速化するために使用できる同様のトリックはありますか?

15
Will Glass

SpringのDAOモジュールを使用して、多くの行をバッチ挿入できます。

1回の更新でOrderオブジェクトのコレクションをデータベースに挿入する例:

public class OrderRepositoryImpl extends SimpleJdbcDaoSupport implements
        OrderRepository {

    private final String saveSql = "INSERT INTO orders(userid, username, coffee, coffeename, amount) "
            + "VALUES(?, ?, ?, ?, ?)";

    public void saveOrders(final Collection<Order> orders) {
        List<Object[]> ordersArgumentList = new ArrayList<Object[]>(orders
                .size());

        Object[] orderArguments;
        for (Order order : orders) {
            orderArguments = new Object[] { order.getUserId(),
                    order.getUserName(), order.getCoffe(),
                    order.getCoffeeName(), order.getAmount() };

            ordersArgumentList.add(orderArguments);
        }

        getSimpleJdbcTemplate().batchUpdate(saveSql, ordersArgumentList);
    }
}
10
Espen

これらのレコードをデータベースに渡す方法にとどまりません。配列を使用するのが最善の方法です。これにより、Oracleの多くの気の利いたFORALLバルク操作を使用できるようになります。

このサンプルパッケージには2つの手順があります。 1つはT23レコードのコレクション(5つの数値列で構成されるテーブル)にデータを入力し、もう1つは配列を使用してそのテーブルにレコードを一括挿入します。

SQL> create or replace package p23 as
  2      type t23_nt is table of t23%rowtype;
  3      function pop_array ( p_no in number )
  4          return t23_nt;
  5      procedure ins_table ( p_array in t23_nt );
  6  end p23;
  7  /

Package created.

SQL> create or replace package body p23 as
  2
  3      function pop_array ( p_no in number )
  4          return t23_nt
  5      is
  6          return_value t23_nt;
  7      begin
  8          select level,level,level,level,level
  9          bulk collect into return_value
 10          from dual
 11          connect by level <= p_no;
 12          return return_value;
 13      end pop_array;
 14
 15      procedure ins_table
 16              ( p_array in t23_nt )
 17      is
 18          s_time pls_integer;
 19      begin
 20
 21          s_time := dbms_utility.get_time;
 22
 23          forall r in p_array.first()..p_array.last()
 24              insert into t23
 25              values p_array(r);
 26
 27          dbms_output.put_line('loaded '
 28                  ||to_char(p_array.count())||' recs in '
 29                  ||to_char(dbms_utility.get_time - s_time)
 30                  ||' csecs');
 31      end ins_table;
 32  end p23;
 33  /

Package body created.

SQL>

いくつかのサンプル実行からの出力は次のとおりです。

SQL> declare
  2      l_array p23.t23_nt;
  3  begin
  4      l_array := p23.pop_array(500);
  5      p23.ins_table(l_array);
  6      l_array := p23.pop_array(1000);
  7      p23.ins_table(l_array);
  8      l_array := p23.pop_array(2500);
  9      p23.ins_table(l_array);
 10      l_array := p23.pop_array(5000);
 11      p23.ins_table(l_array);
 12      l_array := p23.pop_array(10000);
 13      p23.ins_table(l_array);
 14      l_array := p23.pop_array(100000);
 15      p23.ins_table(l_array);
 16  end;
 17  /
loaded 500 recs in 0 csecs
loaded 1000 recs in 0 csecs
loaded 2500 recs in 0 csecs
loaded 5000 recs in 1 csecs
loaded 10000 recs in 1 csecs
loaded 100000 recs in 15 csecs

PL/SQL procedure successfully completed.

SQL>
SQL> select count(*) from t23
  2  /

  COUNT(*)
----------
    119000

SQL>

0.15秒で100,000レコードを挿入することは、最も要求の厳しいユーザーを除いてすべてを喜ばせるはずだと思います。それで、問題は、どのようにあなたの挿入物にアプローチするかということです。

2
APC

今日、MySQLはOracleなので、おそらくもっと簡単な解決策はMySQLにとどまることでしょう...

そうでない場合は、挿入のグループを開始する前にトランザクションが開始されていることを確認する必要があります。グループが終了したら、トランザクションをコミットして、次の挿入グループの新しいトランザクションを開始します。

また、挿入時間を遅くする可能性のある不要なインデックス定義を確認してください。

更新しました...
一括挿入は [〜#〜] etl [〜#〜] (Extract Transform Load)の最後のステップを指しているため、Java pentahoケトル または talend-studio などのベースのETLツール。

Pentahoは、Oracleバルクロード機能について説明しています ここ

簡単なグーグルは、TalendがOracleの一括読み込みもサポートしているという予備的な証拠も示しています。

0
crowne