1

10 以上のデータベース テーブルにまたがる動的検索を実行するストアド プロシージャを作成しています。各テーブルに数百万のレコードがあり、動的な検索パラメーターのセット*があるため、手順を最適化するのに苦労しています。

この種のクエリを作成するための「ベスト プラクティス」はありますか? たとえば、文字列を使用して動的クエリを作成したり、IF THEN .. ELSE ステートメントなどの膨大なリストを使用したりしますか? 誰かが簡単な例を提供したり、役立つ文献を教えてくれませんか? これは、私が開発しているストアド プロシージャの疑似コードです。これは、パラメーターのコレクションと ref カーソルを受け入れます。

v_query = "SELECT .....";
v_name = ... -- retrieve "name" parameter from collection
if v_name is not null then
   v_query := v_query || ' AND table.Name = ' || v_name;
end if;
open search_cursor for v_query;
...

*「検索パラメーターの動的セット」とは、パラメーターのコレクションを渡すことを意味します。呼び出し元が 1 つだけを検索したい場合、呼び出し元に 20 個のパラメーターを渡すよりも簡単だと思いました。

4

4 に答える 4

4

静的クエリ アプローチの使用には問題があります。また、CURSOR_SHARING=FORCE オプションの使用にも十分注意してください。他のすべてのクエリが希望どおりに機能することを確認するカバレッジ テストを行っていない場合、システムが非常に混乱する可能性があります。

静的クエリの問題:

  1. (x is null または x = col) 述語は、インデックスを使用する可能性をなくす傾向があります。クエリ プランはクエリが最初に解析されるときに計算されるため、使用するインデックスはクエリの最初の実行の値に基づきます。同じ列に制約されない可能性がある後の実行でも、同じインデックスが使用されます。

  2. 置換変数を含む静的ステートメントが 1 つあると、オプティマイザーがデータ分散に基づいて使用するインデックスを適切に選択できなくなります。動的クエリ (またはバインド変数を使用したクエリの最初の実行) では、Oracle は制約がどの程度選択的であるかを確認します。高度に選択的な制約は、索引の使用の最有力候補になります。たとえば、テーブルに米国内のすべての人の行がある場合、STATE='Alaska' は STATE='California' よりも STATE のインデックスを使用する可能性が高くなります。

もちろん、どちらの場合でも、WHERE 句の動的列にインデックスが付けられていなくても問題ありませんが、あなたが話しているサイズのデータ​​ベースでそうであった場合は驚くでしょう。

また、すべての難しい解析の実際のコストを考慮してください。はい、ハード解析はシステム リソースをシリアル化するため、コストが高くなりますが、大量のクエリのコンテキストでのみ使用できます。その性質上、アドホック クエリは頻繁には実行されません。1 日に発生するすべてのハード パースに対して支払うコストは、間違ったインデックスを使用する単一のクエリのコストよりも数百分の 1 になる可能性があります。

過去に、私はあなたがここで行ったのとほとんど同じようにこれらのシステムを実装しました - 基本クエリ部分、次に制約リストを反復処理し、WHERE 句の述語を追加しました。FROM 句に多くのサブクエリや余分なテーブルを追加する必要のない制約について話している場合は特に、誰かが維持または理解するのは難しいとは思いません。

考慮すべき 1 つの点: このシステムが主にオフラインのシステムである場合 (つまり、定期的に大量のデータが読み込まれるため、常に更新または挿入されているわけではない)、BITMAP インデックスの使用を検討することをお勧めします。ビットマップ インデックスは、1 つのテーブルで複数のインデックスを同時に使用できるという点で、通常の B ツリー インデックスとは異なります。これらは、設計時に定義できないさまざまな制約があるこのようなアプリケーションで非常にうまく機能します。ビットマップ インデックスは、個別の値が比較的少ない列 (たとえば、1 つの値がテーブルの 1/1000 以上を構成するなど) にのみ配置する必要があるため、一意の列にはビットマップを使用しないでください。

ただし、マイナス面は、ビットマップ インデックスが挿入と更新のパフォーマンスを著しく低下させることです。ビットマップのベスト プラクティスは、データ ウェアハウス アプリケーションでビットマップを使用することです。ビットマップは、ロード前に削除され、後で再作成されます。

于 2009-06-16T20:22:38.397 に答える
2

非常に特殊な場合を除いて、最適化されたクエリを生成しようとすることはお勧めできません (または可能でさえありません)。私のアドバイスは、可能な場合は動的 SQL を使用しないことです: 読みにくい、デバッグしにくい、最適化するのが難しい、維持するのが難しい。

まず、プロシージャに送信される任意のパラメーターで機能する汎用クエリを作成します。あなたの例によれば、それは次のようなものになります:

SELECT * FROM table WHERE ((v_name IS NULL) OR (table.Name=v_name));

ご覧のとおり、動的 SQL を使用しなくても、このクエリに他のパラメーターを簡単に追加できます。このクエリは、読み取りとデバッグがはるかに簡単です。最適化のヒントについては、DBA にお問い合わせください。

次に、一緒に渡されることが多いことがわかっている特定のパラメータ セットがある場合は、このセットに対して特定のクエリを記述して、特に最適化できます。擬似コード:

IF particular_set
THEN
    /* Specific query */
ELSE
    /* Generic query */
END IF;

難しいのは、ここで特定のクエリをあまり多くしないようにすることです。そうしないと、メンテナンス地獄に陥る可能性があります。

于 2009-06-16T12:59:35.827 に答える
1

あるクライアントに同様の要件がありました。数百万行のテーブルが半ダースあり、ほとんどの列でアドホック検索機能が必要でした。

ソリューションは、検索条件を取得し、検索を実行するための SQL を構築する、テーブルごとに個別のパッケージでした。置き換えられた古いシステムを利用して、ユーザーが行っている最も一般的な検索の種類を発見し、生成されたクエリを調整することで、それらの検索が最適に実行されるようにしました (戦略的な使用によってサポートされています)。インデックスの)。各パッケージは 1 つのテーブルに対するクエリのみを担当するため、そのテーブルで動作するように設計された特定のコードを含めることができます (まれなケースで奇妙なヒントを含む)。

対処する必要がある質問/問題の 1 つは、基準 (例: WHERE SURNAME='SMITH') をハードコーディングするか、バインド変数を使用するかということです。バインド変数を使用するとハード解析が減り、データベース サーバーの負荷が軽減されます。ただし、SQL が動的に生成される場合、バインド変数を使用するのは実際的ではありません。私たちが最終的に行った方法は、設定することでしたCURSOR_SHARING=FORCE(これには独自の欠点があります)。これは、私たちの場合には合理的な妥協でした。

于 2009-06-16T02:15:53.980 に答える
1

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:6711305251199を読む

于 2009-06-16T07:09:00.633 に答える