JavaプログラムはOracleテーブルへの一括挿入を実行しています。100〜200レコードの場合は正常に機能しますが、4000レコードを超える場合はハングします。
クエリを確認したところ、INSERT /*+APPEND*/
初期化。
とは INSERT /*+APPEND*/
そしてINSERTクエリで使用されるのはなぜですか?これが原因でプログラムがハングしていますか?
これはSQLオプティマイザーのヒントです。あなたの場合、それはおそらく影響を与えません。多分それは時期尚早の最適化です。
このヒントは、Oracleのバッファキャッシュをバイパスし、データをデータファイルに直接書き込む、いわゆるダイレクトパスインサートを適用する必要があります。データは最高水準点(HWM)を超えて追加されます-テーブルの空き領域マップを無視して、トリガーは発生せず、制約はチェックされません。一方、このタイプの挿入はブロッキングです。特定のテーブルで同時に使用できるセッションは1つだけです。
ドキュメントからの抜粋:
「APPENDヒントは、VALUES句ではなく、INSERTステートメントのサブクエリ構文でのみサポートされます。VALUES句でAPPENDヒントを指定すると、それは無視され、従来の挿入が使用されます。直接パスINSERTを使用するには、 VALUES句、「APPEND_VALUESヒント」を参照このヒントは、INSERTをSELECTステートメントとして使用する場合にのみ機能します。
insert into <table> SELECT * FROM ....
値を挿入すると、Oracleは警告を表示せずに無視します。新しいOracleバージョンはAPPEND_VALUESヒントもサポートしています。
使用されているヒントを検証するには、ToadまたはSQL Developerを開いて、セッションブラウザーを選択し、その特定のセッションを見つけます。これは、現在のSQLおよびexecプランです。 execプランで"INSERT into TABLE CONVENTIONAL"
のようなものを参照すると、ヒントは無視されます。 "INSERT as SELECT"
が表示されている場合は、ダイレクトパスロードを使用しています。
insert
は通常、テーブル内の最初の空のスペースを探して、新しいレコードを追加します。これによりスペースが節約されますが、操作が遅くなることがあります。
/*+APPEND*/
は hint であり、これによりinsert
ステートメントは常に、より適切な用語がないため、テーブルの最後に新しく挿入された行を追加します。これは一部のスペースを無駄にする可能性がありますが、通常は高速です。テーブルの中央に空の領域が多すぎないことがわかっている場合(つまり、delete
sとupdate
sをあまり実行しない場合)は特に便利です。
/ * +追加* /
使用されているヒントを確認する場合は、その特定のセッションとその現在のSQLおよび実行計画を見つけます。 execプランに「INSERT TO TABLE CONVENTIONAL」などが表示されている場合、ヒントは無視されます。 「INSERT as SELECT」と表示されている場合は、ダイレクトパスロードを使用しています。
これは、Oracleコンパイラのヒントです。目的のためにあり、コメントではありません。このヒントは挿入を高速化するためにそこで使用されているので、プログラムをハングアップさせる原因ではないと思います。
ただし、このテーブルが使用しているテーブルスペースで使用可能な空き領域を確認するようにdbaに依頼してください(dbaはこのステートメントをよりよく理解します:))。
そのテーブルスペースへの挿入に使用できるスペースが非常に少ないという問題がある可能性があります。これは、dbaが解決できるはずです。
利用可能なスペースが少なくなるのはなぜですか? APPENDヒントは@Mureinikによる上記の回答で説明されているようにスペースを浪費し、そのテーブルでこのヒントを使用して頻繁に挿入が多すぎる場合は問題になる可能性があるためです。
挿入の「高速化」については知りませんが、ヒントは間違いなく見つかりました。そうです。これは、Oracleがコメントと呼んでいるものです-から挿入を行うときにレコードの順序を維持するのに非常に役立ちますコマンドを最後にORDER BY
とペアにすると、1つのテーブルが別のテーブルに組み込まれます。
INSERT /*+ append */ INTO MYAPP.COUNTRIES (ID, CODE, NAME)
SELECT ID, CODE, NAME FROM MYAPP.OLD_COUNTRIES_TABLE ORDER BY NAME ASC;
COMMIT;
私はこれが単なる偶然である( this thread on SOを参照)とたたきましたが、何度も何度も使用してきました。 。 INSERT
をORDER BY
と一緒に使用しても、追加のヒントなしでを使用すると、ORDER BY
は無視され、次に、レコードが挿入された順序に従ってレコードを取得できるようにするためにまったく役に立たない( 私の答えの証明、ここ を参照)。