7

パラメータ化されたクエリがあります。パラメータ値によって、最適なクエリ プランは大きく異なります。問題は次のとおりです。Oracle は、最初のクエリ呼び出しからの計画を後続の呼び出しに使用するため、パフォーマンスが低下します。私は動的 SQL で処理しますが、この方法はエレガントとは言えません。問題は、クエリ プランを再計算する必要があることを Oracle に伝える方法があるかどうかです。

4

7 に答える 7

5

パラメータ値によってクエリ プランが実際に大幅に変更される場合は、このパラメータにバインド変数を使用しないでください。

そのパラメータはいくつの異なる値を取ることができますか? 数が少ない場合は、いくつかのクエリ プラン (値ごとに 1 つ) になり、うまく機能して再利用できることが期待されます。

または、SQL ステートメントでコメント "/* THIS IS VALUE BRACKET ONE * /" を使用してそれらを区切ることもできます (またはクエリ アナライザーのヒント。どれが適切かわかっている場合は、/*+ CARDINALITY */ のようなものが適用される可能性があります)。ここ)。

いずれにせよ、あなたは本当にそのクエリを微調整したいように見えるので、Statspack とその仲間で別々のレポートを取得できるように、別々の SQL ステートメントが必要だと思います。

于 2009-04-07T07:58:57.817 に答える
4

Oracle 10g の場合、クエリで任意のテーブルを選択して実行します

GRANT SELECT ON table1 TO user1;

これにより、このテーブルを参照するすべてのクエリのプランが無効になります。もちろん、他のクエリへの影響が最小限のテーブルを選択する必要があります。詳細とサンプル リストについては、このページも参照してください。

于 2009-04-07T07:47:39.327 に答える
2

オプティマイザーが使用するものの 1 つは、関連する列のヒストグラムです。バインド変数を使用していて、関連する列にヒストグラムがある場合、パラメーター値によって計画が変わる可能性があります。この最初の計画は共有プールに残り、すべての値に使用されます。

これを望まない場合は、バインドの代わりにリテラルを使用できます (同じ SQL のバージョンが多すぎない場合)。または、ヒストグラムを削除することもできます。ヒストグラムを削除すると、バインド パラメータ値に関係なく、同じ計画が生成されます。

実行ごとに sql を無効にすることはお勧めできません。この sql の使用頻度によっては、ハード解析によるラッチの問題など、新たな問題が発生する可能性があります。

于 2009-04-07T13:44:16.113 に答える
2

クエリ プランを再計算する必要があることを Oracle に伝える方法はありますか?

異なる実行計画に対して複数の を作成しOUTLINE、 を使用して使用するものを選択できますOUTLINE CATEGORIES

CREATE OUTLINE ol_use_nl
FOR
SELECT  *
FROM    mytable1 mt1
JOIN    mytable2 mt2
ON      mt1.id = mt2.id
WHERE   mt1.value BETWEEN :a AND :b
CATEGORY FILTERED;

/* Edit the outline to add USE_NL */

CREATE OUTLINE ol_use_nl
FOR
SELECT  *
FROM    mytable1 mt1
JOIN    mytable2 mt2
ON      mt1.id = mt2.id
WHERE   mt1.value BETWEEN :a AND :b
CATEGORY UNFILTERED;

/* Edit the outline to add USE_HASH */

ALTER SESSION SET USE_STORED_OUTLINES = FILTERED;

SELECT  *
FROM    mytable1 mt1
JOIN    mytable2 mt2
ON      mt1.id = mt2.id
WHERE   mt1.value BETWEEN 1 AND 2

/* This will use NESTED LOOPS */

ALTER SESSION SET USE_STORED_OUTLINES = UNFILTERED;

SELECT  *
FROM    mytable1 mt1
JOIN    mytable2 mt2
ON      mt1.id = mt2.id
WHERE   mt1.value BETWEEN 1 AND 1000000

/* This will use HASH JOIN */
于 2009-04-07T14:38:51.037 に答える
2

本当に毎回新しいクエリ プランを生成したい場合は、thilo が提案するように一意のコメントを入力してください。

select /* SQLID=1234 */ 1 from dual;
select /* SQLID=1235 */ 1 from dual;

これらは独自の計画を生成する必要があります。

オプティマイザーを回避しようとする前に、統計が間違っていないことを十分に確認する必要があります。

于 2009-04-07T08:18:10.657 に答える
0

OPは、SQLステートメントを変更できないことを示しています。パッケージを使用するとdbms_advanced_rewrite、SQL ステートメントをインターセプトし、この SQL ステートメントを変更することができます。

于 2009-04-09T18:55:51.970 に答える
0

あなたの問題は、バインド変数のピークが原因です - データベース全体に対してそれをオフにすると、おそらく他のことが壊れますが、次のヒントを追加することで、このクエリだけに対してそれをオフにすることができます:

/*+ opt_param('_OPTIM_PEEK_USER_BINDS',FALSE) */

于 2009-04-07T15:22:56.690 に答える