3

非常に大きな(数百万行の)テーブルをあるDB2DBから別のDB2DBに毎日コピーする必要があり、perlとDBIを使用する必要があります。

これを行うには、最初のDBから各行を単にfetchrow_arrayして、2番目のDBに1つずつ挿入するよりも速い方法がありますか?これが私が得たものです:

$sth1 = $udb1 -> prepare($read_query);
$sth1 -> execute();
$sth1 -> bind_columns(\(@row{@{$sth1 -> {NAME_1c}}}));

$sth2 = $udb2 -> prepare($write_query);

while ($sth1 -> fetchrow_arrayref) {
    $sth2 -> execute($row{field_name_1}, $row{field_name_2});
}

同様のスレッドからいくつかのソリューションを実装しましたが、それでも遅いです。確かにもっと良い方法が必要ですか?

4

4 に答える 4

5

これを 1 つのトランザクションにラップすると、はるかに高速に動作するはずです。次のようなものを使用します。

$sth1 = $udb1->prepare($read_query);
$sth1->execute();
$sth1->bind_columns(\(@row{@{$sth1->{NAME_1c}}}));

$udb2->begin_work();
$sth2 = $udb2->prepare($write_query);
while ($sth1->fetchrow_arrayref()) {
    $sth2->execute($row{field_name_1}, $row{field_name_2});
}
$udb2->commit();

何百万行もある場合は、数千行ごとにコミットを実行することをお勧めします。

さて、それがより速い理由:

あなたの場合、すべての挿入は 1 つの自動コミットされたトランザクションです。言い換えれば、サーバーは、数百万行のすべての変更が実際にディスクにフラッシュされるまで待機する必要があります-非常に遅いです!

それをトランザクションにラップすると、サーバーは一度に数千行をディスクにフラッシュできます - はるかに効率的かつ高速です。

(まったく同じテーブルを何度もコピーする場合は、代わりにある種の一意のキーで変更を同期する方が賢明です。100 万倍速くなるはずです)。

于 2013-01-08T07:22:18.990 に答える
1

これを毎日行っているのであれば、DB2exportimportユーティリティが最適だと思います。その方法は、複数の SQLステートメントよりもはるかに高速になる可能性があります。INSERT

DBIPerl のモジュールを使用してこれを行うことは可能ですがsystem、Perl スクリプト内から実行する必要がある場合は、またはバッククォートを使用する必要がある場合があります。

于 2013-01-08T10:27:29.010 に答える
1

ソース データベースのコンテンツをファイルに送信できる場合は、LOAD コマンドまたは INGEST ユーティリティを使用できます。ログを使用しないため、LOAD は非常に高速です。INGEST は通常の挿入ですが、再開できます。

これらのコマンドは Perl から呼び出すことができ、あとは DB2 が行います。

ただし、ソース データベースとターゲット データベースが DB2 の場合は、ソースをターゲットに統合できます。つまり、ターゲット データベースに (ソースからの) リモート テーブルが表示されます。この場合、LOAD を呼び出すだけで済みます。DB2 -> Perl -> DB2 ではなく、DB2 と DB2 の間で通信が行われるため、これが最も高速です。

大きなテーブルを処理するために DB2 を残しておく方がよいと思います。その中間に Perl があります。メモリが爆発したり、コミットが問題になったりする可能性があります。

また、DB2 のライセンスによっては、Optim High Performance Unload を使用して、SQL 経由ではなくテーブルスペースから直接テーブルを抽出することもできます (低速)。

于 2013-01-08T15:26:21.150 に答える
1

ここで mvp が言ったことに加えて、DBI ドキュメントからのスニペットがあります。

 my $sel = $dbh1->prepare("select foo, bar from table1");
  $sel->execute;

  my $ins = $dbh2->prepare("insert into table2 (foo, bar) values (?,?)");
  my $fetch_tuple_sub = sub { $sel->fetchrow_arrayref };

  my @tuple_status;
  $rc = $ins->execute_for_fetch($fetch_tuple_sub, \@tuple_status);
  my @errors = grep { ref $_ } @tuple_status;

mvp の回答と組み合わせると、特に DBD::DB2 に独自の execute_for_fetch メソッドがある場合 (これはわかりません)、さらに高速になるはずです。独自の execute_for_fetch メソッドを持つ DBD は、通常、操作をバッチ処理します。ただし、とにかく少し速くする必要があります。

于 2013-01-08T08:52:26.460 に答える