多くの小さな行を Oracle にすばやく挿入する必要があります。(5 フィールド)。
MySQL では、挿入を 100 個のグループに分割し、100 個の挿入のグループごとに 1 つの挿入ステートメントを使用します。
しかし、Oracle では、大量の挿入 (1000 ~ 30000 のどこでも) が遅すぎるというユーザー フィードバックが寄せられています。
JavaからOracleへのプログラムによる挿入を高速化するために使用できる同様のトリックはありますか?
多くの小さな行を Oracle にすばやく挿入する必要があります。(5 フィールド)。
MySQL では、挿入を 100 個のグループに分割し、100 個の挿入のグループごとに 1 つの挿入ステートメントを使用します。
しかし、Oracle では、大量の挿入 (1000 ~ 30000 のどこでも) が遅すぎるというユーザー フィードバックが寄せられています。
JavaからOracleへのプログラムによる挿入を高速化するために使用できる同様のトリックはありますか?
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);
}
}
これらのレコードをデータベースに渡す方法はわかりません。最良の方法は、配列を使用することです。これにより、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 件のレコードを挿入できれば、最も要求の厳しいユーザー以外は満足できるはずです。では、問題は、インサートにどのようにアプローチするかということです。
現在、MySQLはOracleであるため、おそらくより簡単な解決策はMySQLにとどまることかもしれません...
そうでない場合は、挿入のグループを開始する前にトランザクションが開始されていることを確認する必要があります。グループが終了したら、トランザクションをコミットして、次の挿入グループの新しいトランザクションを開始します。
また、挿入時間を遅くしている可能性のある不要なインデックス定義を確認してください。
更新...一括挿入はETL
(Extract Transform Load)
の最後のステップを指しているため、 pentahoケトルやtalend-studioなどのJavaベースのETLツールの使用を検討しましたか。
Pentahoは、Oracleバルクローディング機能についてここで説明しています。
簡単なグーグルは、TalendがOracleの一括読み込みもサポートしているという予備的な証拠も示しています。