Oracle 11g:挿入のパフォーマンス改善


8

5億行のテーブルがある(そして成長している)

挿入のパフォーマンスを向上させるために次のことを行いました。

データベース側:

  • すべてのインデックスと制約を削除
  • ロギングを無効化

アプリケーション側:

  • JPA管理エンティティからネイティブ挿入クエリに切り替え、クエリにAPPEND Oracleヒントを追加
  • 1k / 2k / 3k行ごとにバッチでコミットしようとしました
  • 1つのテーブルに並列に(複数のスレッド、スレッド数=サーバーのコア数に)書き込もうとした

これは私に毎秒約300行を与えました

さらに試しました:

  • 複数のテーブルにバッチで並行して書き込む(UNIONを使用して結果をグループ化して戻す)

これにより、1秒あたり約1k行が得られましたが、空のテーブルにあります。しかし、テーブルにダミーデータ(それぞれ2億個)を入力すると、挿入速度が1秒あたり250〜300に低下しました。

誰かが挿入を高速化するために他に何ができるかを提案できますか?基本的に私は最初にボトルネックが何であるか(何であるか)を理解したいと思います。

UPD: テーブルは挿入日によってパーティション化され、テーブルには約60列があります-ほとんどの列はVARCHAR2(2000 BYTE)です


ロギングが無効になっていると、ロードとその後の最初のバックアップが完了するまでの間にメディア障害が発生すると、テーブル全体またはテーブルのセクションがそのまま残ります。
David Aldridge 2013年

1
(1)テーブル上で同時に追加できるセッションは1つだけです。(2)/*+APPEND*/単一行の挿入では、ヒントは無視されます(INSERT INTO ... SELECT追加する必要がない場合)。(3)direct=true@parsifalによって提案されたベースラインを確立するために、SQL * Loaderの例をセットアップする必要があります。
Vincent Malgrat 2013年

実際のハードウェアまたは仮想マシンで実行していますか?VMの場合、ディスクファイルはまばらですか(つまり、完全に事前割り当てされていません)?また、statspackまたはawrレポート(上位の待機セクション)からの出力で質問を編集してください。
フィロ2013年

挿入日による分割はどのような問題/ニーズを解決/満足しますか?
ブライアン

このテーブルのデータのソースは何ですか?これは、ASCIIファイルからのバッチロードですか、それともユーザーが生成したものですか。具体的にご記入ください。
RMAN Express

回答:


5

更新を見たところ、ほとんどがVARCHAR(2k)フィールドを持つ60列のテーブル、つまり(潜在的に)モンスターテーブルです。

まず最初に ...

最初にボトルネックを理解する必要があります。アプリ側で、シングルスレッドのバッチ挿入ソリューション(一度に1/2 / 3k)に戻って実行を開始し、DBマシンにログインして「トップ」を実行します-どれだけかを確認してくださいDBプロセスにかかっている時間と、マシンが表示している時間(ある場合)の割合。

topがwa%時間を示している場合、それはDBがI / Oにバインドされていることを意味し、複数のDBマシン(シャード)を検討するか、ホストマシンにSSDをスローすることを検討する必要があります。

それでおしまい; あなたの研究はここで止まります。DBが使用しているCPUの量やアプリクライアントの飽和状態は関係ありません。ホストDBでI / Oレイテンシの問題が発生している場合は、それはこれまでにないほど高速です。

ヒントハードウェアの変更が問題にならない場合は、実行しているファイルシステム(Linux)に応じて、DBのロギングまたはメタデータの書き込みを無効にして、ファイルシステムレベルでのパフォーマンスをわずかに向上させることができます。NTFSでも同様のことを行うことができますが、これは少しだけ向上します。これは2倍にはなりません。

さて、2番目のことは2番目です...

wa%の時間はほとんどなかったが、CPUがDBプロセスによって完全にペグされているとしましょう。現在の唯一の選択肢は、より多くのDBマシン(シャード)を導入して作業を分割することです。

繰り返しになりますが、これが事実であれば、これで調査は完了です。CPUを調整して高速化するためにできることは何もありません。

最後に、第三のこと...第三...

DBが何も実行していないとしましょう。次に、バッチ挿入を実行しているクライアントマシンに移動して、CPU負荷を確認します。その場合は、まったく同じバッチ挿入を実行するいくつかのマシンを起動して、直線的な傾斜が得られるかどうかを確認します。

CPUがペグされていない場合は、ペグされるまで同じマシンでさらにいくつかのスレッドを起動し、DBのスケーリングを確認します。

私はあなたがすでにそれを試したかもしれないと思うので、私の推測はあなたのクライアントホストがすでにペグされていて(そしてより多くのスレッドは違いをもたらさないでしょう)、またはDBはすでにその限界に達しており、これ以上スケーリングすることができないと思います。

補遺

ガベージが含まれていないインデックス付けされていないテーブルでraw挿入を行うことは、本質的にはAPPEND操作であり、ディスクが書き込みを処理できるのと同じ速さで実行する必要があります。

同じホストマシンでさらにテーブルを作成しても、ディスクシークが増加し(ディスク上の他のテーブルに追加して追加するため)、何かが遅くなると、役に立ちません。

最初にそのボトルネックを理解し、それから地獄を最適化することが重要です。

お役に立てば幸いです。投稿してください。


2
なぜawrやstatspackについて言及しなかったのですか?
Philᵀᴹ

追加ヒントを使用すると、これらのスレッドの1つを除くすべてが、排他ロックのためにアイドル状態になります。このコードは、システムレベルのチューニングが必要な効率の段階にあるとは思いません。欠陥があるのは方法論自体です。
David Aldridge 2013年

さらに考えると、あなたのアプローチには根本的な欠陥があると思います。Viktorsがシングルスレッドのバッチ挿入メソッドを試行し、I / O待機時間があった場合、非効率的な挿入メソッドとオーバーコミット(ログファイルの同期待機)が原因である可能性があります。最も重要なステップは、Oracleのメカニズムを理解し、最も適切なメカニズムを最初に選択することです。
David Aldridge 2013年

@DavidAldridge Viktorsは、ログ(およびインデックス)を無効にしたことを明らかにしたので、挿入されたデータをテーブルファイルに直接ストリーミングする以外に、DBは他に多くのことをしていないと想定しました。 I / O待機。おそらく、無効にする必要がある、または無効にすることができるOracleが他にもあります。これは良い調査ポイントです。残念ながら、Oracleの深さを十分に理解していないので、それを助けることはできません。
リヤドカラ2013年

4

追加ヒントを使用してダイレクトパス挿入を呼び出すと、テーブル全体に対して排他ロックがかかるため、挿入を実行する複数のスレッドを用意しても役に立たない。挿入ごとに異なるパーティションを明示的にアドレス指定する必要があります...

insert /*+ append */ into my_table partition (partition_name_1) ...

...パーティションレベルの排他ロックを取得します。ほとんどの場合、挿入日にパーティション分割されたテーブルを使用してこれを行うことはできませんが、サブパーティションではなく複合パーティションを使用して、挿入日付の一意の範囲ごとに複数のパーティションを取得できます。

挿入の途中ではなく、最後にコミットしないでください。


クエリでパーティション名を明示的に言及する必要がありますか?イベントタイプのような列があります。私はイベントのグループによってパーティションにしようとすると、各スレッドは、特定のタイプの行のバッチを挿入しているようにするつもりです
漂流

テーブルレベルの排他ロックを回避するには、はい。
David Aldridge

単一行の挿入の場合、APPENDヒントはOracleによって無視されます。OPによるプロセスの説明は、単一行のバッチ挿入を意味するようです。しかし、それらがどのように扱われるかはわかりません。APPENDはないと思いますが、いくつかのテストが必要です。
Vincent Malgrat 2013年

うーん、それは考慮していませんでした。
David Aldridge 2013年

APPENDヒントを使用して複数行の挿入を試す価値はありますか?次に、複数行挿入ごとにいくつのエントリを送信する必要がありますか?
漂流
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.