OracleBulkCopyの具体的な機能とパフォーマンスを最適化するにはどうすればよいですか?


14

詳細を要約すると、約500万行をベンダー(Oracle)データベースにステージングする必要があります。OracleBulkCopy(ODP.NET)を使用して50万行のバッチですべてがうまくいきますが、5Mにスケールアップしようとすると、1Mマークに達するとパフォーマンスが低下してクロールになり、行がロードされるにつれて徐々に遅くなり、最終的には3時間程度でタイムアウトします。

テーブルの主キーに関連していると思われますが、情報と私が読んでいる多くのことのためにOracleフォーラムとStack Overflowを探し回っています(また、多くの投稿が互いに矛盾しているようです) 。私は誰かがプロセスに関するいくつかの密接に関連した質問にまっすぐに記録を立てることができることを望んでいます:

  1. ないOracleBulkCopyクラスは、従来の、またはダイレクト・パス・ロードを使用しますか?何らかの方法でこれを確認できますか?

  2. 仮定すると、それはありません使用ダイレクト・パス・ロード:それはOracleが自動的にロードおよびプットバックオンラインその後、それらの間に使用不可能にすべてのインデックスを設定していることは本当ですか?私はこの効果に関するいくつかの声明を読みましたが、繰り返しますが、確認することはできません。

  3. #2がtrueの場合、一括コピー操作を開始する前に、テーブルにどのインデックスが存在するか違いがありますか?もしそうなら、なぜですか?

  4. #3に関連して、一般に、使用できないインデックスを使用したバルクロードと、ロードの前に実際にインデックスを削除してから再作成する間に、実際的な違いはありますか?

  5. #2が正しくない場合、または理解していないいくつかの警告がある場合、バルクロードの前に明示的にインデックスを使用不可にし、その後 明示的に再構築することは違いがありますか?

  6. インデックスビルド以外に、レコードが追加されるにつれて一括コピー操作が徐々に遅くなる原因はありますか?(たぶん、ロギングと関係がありますが、バルク操作はログに記録されないと思われますか?)

  7. 最初にPK /インデックスを削除する以外にパフォーマンスを完全に向上させる方法が他にない場合、インデックスが完全に消えないようにするためにどのような手順を実行できますか。つまり、データベースへの接続が失われた場合プロセスの途中?


サイドノート:コピーされるデータは、テーブル上の唯一のインデックスであるPKに従って既にソートされています。
アーロンノート

ソースからデータを読み取るためにDataReaderを使用していますか?
bernd_k

@bernd_k:いいえ、完全にメモリから読み込みます。問題の原因は明らかにソースではありません。
アーロンノート

回答:


13

さらに数日間の読書と実験で、私はこれらの多くに(ほとんど)答えることができました。

  1. これはODP.NETのドキュメントに埋もれています(皮肉なことOracleBulkCopyドキュメントにはありません):

    ODP.NET一括コピー機能は、Oracle SQL * Loaderに似ていますが、同じではないダイレクト・パス・ロードのアプローチを使用します。ダイレクトパスロードの使用は、従来のロード(従来のSQL INSERTステートメントを使用)よりも高速です。

    そのため、直接パスを使用しているようです。

  2. これは、大規模な一括コピー操作を実行し、SQL Developerからインデックスプロパティを取得することで確認できました。インデックスがなかったとして現れUNUSABLE一括コピーが進行中でした。 しかし、私はまたOracleBulkCopy.WriteToServer、インデックスが開始UNUSABLE、インデックスを無効にして再構築など、簡単なようであれば、それは初期状態を気にしないはずなので、そうはっきりとより多くのここが起こって、状態。

  3. インデックスも制約である場合特に違いが生じます。上記のリンクのドキュメントでこの小さな宝石を見つけました。

    有効な制約
    Oracle一括コピー中に、次の制約がデフォルトで自動的に有効になります。

    • NOT NULL
    • UNIQUE
    • PRIMARY KEY (非ヌル列の一意制約)

    NOT NULL制約は列配列のビルド時にチェックされます。NOT NULL制約に違反する行は拒否されます。

    UNIQUEロードの最後にインデックスが再構築されると、制約が検証されます。UNIQUE制約に違反する場合、インデックスはIndex Unusable状態のままになります。

    ドキュメントには、何が起こるかに少しかすんでいる時に、特に主キーで、負荷が、一つのことは絶対に確かである-それは異なった動作をして、主キー対なしの 1。OracleBulkCopyインデックスの制約に違反することを喜んで許可するので(そしてUNUSABLE完了したらインデックスを状態にパントします)、私の考えでは、バルクコピー中にPKインデックスを構築していますが、検証し、その後までそれを。

  4. 観察された違いがOracle自体にあるのか、それとも単なる奇抜なのかはわかりません OracleBulkCopy。審査員はまだこれについて出ています。

  5. OracleBulkCopy インデックスが最初にある場合、例外をスローします UNUSABLE状態にある。したがって、それは本当に論点です。

  6. もしそこにあるなら ある他の要因が、私がで分かったように、インデックス(特にPKインデックス)は、今でも最も重要です。

  7. 同じスキーマを使用してグローバル一時テーブルを作成し(を使用CREATE AS)、一時テーブルに一括コピーし、最後に単純な古いテーブルを作成しますINSERTに一時テーブルから実際のテーブルにを実行します。一時テーブルにはインデックスがないため、一括コピーは非常に高速に行わINSERTれ、データは既にテーブルにあるため、ファイナルも高速です(5M行のテーブルからテーブルへのコピーなので、まだ追加ヒントを試していません)すでに1分もかかりません)。

    この方法で一時表スペースを使用することによる(ab)の潜在的な影響についてはまだわかりませんが、これまでのところ問題はありませんでした。また、いずれかの行の破損を防ぐことで、代替よりもはるかに安全です またはインデックス。

    これの成功は、PKインデックスが問題であることをかなり明確に示しています。これは、一時テーブルと永続テーブルの唯一の実際的な違いであり、両方ともパフォーマンステスト中にゼロ行で開始しました。

結論: ODP.NETを使用して、インデックス化されたOracleテーブルに約10万行以上を一括コピーしようとしないでください。インデックスを削除する(実際に必要ない場合)か、データを別の(インデックス化されていない)テーブルに「プリロード」します。


主キー制約の確認についてはわかりません。同じデータをOracleテーブルに2回バルク挿入するために、2回重複して選択すると、重複した行が2つ表示されます。その状態では削除はできませんが、truncate tableはクリーンな状態に戻すのに役立ちます。
bernd_k

@bernd_k:Deleteはインデックスがのため、不可能ですUNUSABLE。これは、一括コピーの最後に発生する制約チェックの結果です。
アーロンノート

PowerShell skriptを実行して、SQL ServerデータリーダーからOracleデータベースにbulkcopyを呼び出し、すべてのターゲットテーブルにプライマリキーがあり、最大205278行のテーブルに問題はありません。しかし、詳細テーブルを埋める前に、最初にマスターテーブルを一杯にすることに非常に注意しています。テーブル上の他のインデックスを削除しなかったため、テーブルが最初に空のときは問題ありません。
bernd_k

@bernd_k:はい、そのボリュームでもあまり問題はありませんでした(私の最後の段落を参照)。ひどくなるのは、数百万に達するときです。また、各バルクコピーの後にテーブルを空にした場合も違いがあります(このテーブルは空にならず、追加され、インデックスが大きくなるにつれてインデックスが遅くなる方法を知っています)。
アーロンノート

あなたが行うとき、多分それは役立ちますalter session set skip_unusable_indexes = true;
Wernfried Domscheit

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.