
Oracle SQLチューニング Season2(第23回)第4章 SQL TuningとHINTの関係 (6/8)
今回のSQLチューニングブログ2nd Season(第23回)は、「SQL Tunig と HINTの関係」の第6回目です。
~ INSERT制御のヒント ~ について解説していきます。
それでは早速、はじめていきましょう。
4.2.9 INSERTコントロールヒント
Insert文にヒントを適用する事は、Insert操作の対象データが多く、操作の速度を改善するためのヒントを適用することを意味します。
大量のデータをInsertする作業は、他のDML作業とは違って性能改善の余地が多くあります。
なぜそのように考えるべきなのでしょうか?・・・・
それは、データ入力対象テーブルの属性変更(Nologging)とヒント(/+ append */)だけでDirect Path Insertを誘導してREDO発生量を抑制する方法があるからです。
・APPEND
使用バージョン:8.1.0〜。
使用方法: /+ APPEND */ (Inverse: NOAPPEND)
ヒント意味: Insert ~ Select構文がDirect Mode Insertで実行されるようにするヒント。
APPENDヒントを適用すると、対象セグメントのHigh Water Markの後にInsertとなり、Direct LoadでINSERTが実行されます。
APPEND使用時、Archive Log ModeであるDBにおいて明示的にNOLOGGINGオプションを一緒に追加する形でヒントを使用することで、リードデータを発生させること無く、より速いINSERT作業が期待できます。
しかし、テーブルに複数のインデックスが存在する場合、期待した効果に満たない性能が発生することがあります。
これは、大量のINSERT作業時、データがテーブルに入力される作業よりも、インデックスの数と性質によって性能が左右されると言っても過言ではないからです。
下記の2つの例を使って、Direct Path Insertが可能な環境における大量のINSERT作業の性能差と、これを改善するための方法について説明していきたいと思います。
TEST 1 : Appendヒントの使用有無によるInset性能比較
約365万件に相当する大量のデータをINSERTする際、APPENDヒントを使用せずにREDOデータの生成を含めてINSERT作業を行った結果、約42秒程度の応答時間と約800MBのREDOデータが生成されました。
一方、テーブル属性を”Nologging”に変更してから APPENDヒント を適用すると、応答時間は7秒程度、約4MBのREDOデータが生成される結果となりました。
このように大量のデータをInsertする作業においては、APPENDヒントの存在感は絶対的なのです。
したがって、このような作業を行う場合には、APPENDヒントの積極的な使用を検討する必要があります。
TEST 2 : Indexが存在する場合のInsert性能比較
上記のテスト結果から、大量のデータがINSERTされる時、そのテーブルに複数のインデックスが作成されているとパフォーマンスに大きな影響を与えることが分かりました。
インデックスが3つ存在する場合、18,260,000件をINSERTするのにかかった時間は8分50秒ほどです。
一方、既存のインデックスを削除後、同じデータをINSERTした場合では、所要時間は25秒程度となり、大幅な時間短縮が実現できることがわかりました。(その後、削除した3つのインデックスを再作成するのにかかった時間を含めて計算した場合でも短時間で実行されました)
上記のテスト結果を踏まえて、焦点に当てて見ていくべき要素には、実行時間以外のREDO発生量があります。
インデックスがある場合、約210 MBのREDOが発生し、インデックスがない場合では、REDO発生量は約1.8 MBとなり大幅に減少することがわかりました。 つまりこの結果から、REDO発生量の違いによるINSERT性能に差が発生したと結論付けることができます。
上記のテストでは、単純に大量のデータが入力されるすべての作業にインデックスをDROPしたり、UNUSABLE状態に変更して作業しなさいという意味ではなく、APPENDヒントはテーブルにINSERTされるデータがDirece Loadで入力され、それだけREDO発生量が減ることになりますが、インデックスが発生させるREDOは制御されないため、インデックスがたくさん生成されているテーブルに対するAPPENDヒントは性能改善に限界があることを示すためことを意味します。
・APPEND_VALUES
使用バージョン:11.2.0.1〜。
使用方法: /*+ APPEND_VALUES */ (Inverse: NOAPPEND)
ヒント意味: Insert ~ Values (1件) 構文がDirect Mode Insertになるようにするヒント。
Direct Path ModeのInsertは、Oracle 11g以前までは”INSERT ~ SELECT”構文に/*+ APPEND */ヒントを使用することで可能でしたが、”INSERT ~ VALUES”構文(1 Row Insert)には対応していませんでした。
ところが、Oracle 11gからはAPPENDヒントとAPPEND_VALUESヒントを適用すると、”INSERT ~ VALUES” (1 ROW INSERT) InsertをDirect Path Modeで実行できるようになりました。Oracle 11gR1までは”INSERT ~ VALUES”構文にAPPENDヒントを付与すればよく、Oracle 11gR2はAPPENDヒントに代わるAPPEND_VALUESヒントが新たに追加され、これを使用すればよいことになります。
しかし、少数のデータをInsertする時、本当にAPPEND_VALUESヒントを適用することが性能上で有利となのか考えてみる必要があります。
Direct Path ModeでInsert操作を実行することは、同じテーブルに他のInsert操作が実行されるときにBlockingが発生し、Direct Path Modeの特性上、Physical I/Oが発生し、High Water Mark以降にデータが入力されるため、ある程度のFragmentation(断片化)現象のオーバーヘッドが発生することを意味します。したがって、少ない数のデータに対するInsert作業をDirect Path Modeで実行することは、むしろ性能上不利であると言えます。
しかし、Insert ~ Select ~構文と似たような動作をするArray Processingを活用したBulk Insertを実行する場合は話が違ってきます。下記の例を通じて、1件のデータがInsertされる場合とArray Processingを活用したBulk Insertが実行される場合にConventional Path ModeとDirect Path Modeの性能の違いをそれぞれ見てみましょう。
テスト[1].1 Rowに対するREDO発生量の比較
上記のテスト[1]の結果のように、1RowデータをINSERTする場合は、Direct Path Modeに比べてConventional Path ModeでINSERTする方がより良い性能を示しました。 つまり、1ROWずつデータINSERTにはAPPEND_VALUESヒントは効用を持ちません。
テスト[2].BULK INSERTに対するREDO発生量の比較
テスト[2]のFORALLを利用したBULK COLLECT INSERT時、APPEND_VALUESヒントの効率性チェック部分を見ると、2つのプロシージャは全て同じ量のデータをINSERTするArray Processingを活用したBULK INSERT構文です。
それぞれを実行した後、REDO発生量を調査してみると、P_INSERTプロシージャは約1.9 MB程度で、P_APPEND_VALUES(APPEND_VALUESヒント適用)プロシージャは約1.6 MB程度で多少減少した結果となりました。
このテスト結果から推測すると、多くのデータに対するINSERT作業時、大きな違いは見られませんが、BULK INSERT作業にはAPPEND_VALUESヒントを使用すれば、REDO発生量を減らすことができることが証明されました。
次回のSQLチューニングブログは・・・
SQLチューニングブログ2nd Season(第4章)
「SQL Tuning と HINTの関係」(7/8)
~ PARMETER制御のヒント・SQL PERFORMANCEに関するヒント・QUARY OPTIMIZINGに関するヒント ~