5

ばかげた質問の時間。Oracle10g。

where句が結合に影響を与える可能性はありますか?

次の形式のクエリがあります。

select * from
(select product, product_name from products p
join product_serial ps on product.id = ps.id
join product_data pd on pd.product_value = to_number(p.product_value)) product_result
where product_name like '%prototype%';

明らかに、これは不自然な例です。テーブル構造はすべて架空のものであるため、実際に表示する必要はありません。残念ながら、実際のテーブル構造やクエリを表示することはできません。この場合、p.product_valueはVARCHAR2フィールドであり、特定の行にはテキストではなくIDが格納されています。(はい、悪いデザインですが、私が継承したもので、変更できません)

問題は参加にあります。where句を省略すると、クエリが機能し、行が返されます。ただし、where句を追加すると、pd.product_value = to_number(p.product_value)結合条件で「無効な番号」エラーが発生します。

明らかに、「無効な番号」エラーは、p.product_valueフィールドに数字以外の行が含まれている行が結合されたときに発生します。しかし、私の質問は、それらの行がどのように選択されているかということです。結合がouterwhere句なしで成功した場合、outer where句は結合の結果から行を選択するだけではいけませんか?結合が内部クエリにあるにもかかわらず、where句が結合される行に影響を与えているようです。

私の質問は理にかなっていますか?

4

4 に答える 4

2

生成される計画に影響します。

テーブルが結合される(したがってフィルタリングされる)実際の順序は、クエリを作成する順序ではなく、テーブルの統計によって決まります。

あるバージョンでは、偶然に生成された計画は、「不良」行が処理されないことを意味します。これは、先行する結合によって、結果セットが結合されないポイントまでフィルタリングされたためです。

この句の導入により、WHEREORACLEは、結合の順序が異なる方が良いと考えていることを意味します(製品名によるフィルタリングには特定のインデックスが必要なため、またはデータを大幅に絞り込むためなど)。

この新しい順序は、「不良」行が、それらをフィルターで除外する結合の前に処理されることを意味します。


クエリを実行する前に、データをクリーンアップするように努めます。おそらく、値がすでに数値にキャストされている派生列を作成するか、それが不可能な場合はNULLのままにします。

EXPLAIN PLANを使用して、クエリから生成されているさまざまなプランを確認することもできます。

于 2012-04-10T15:07:02.253 に答える
1

簡単な答え:はい。

長い答え:クエリエンジンは、同じ結果を返す限り、クエリを自由に書き直すことができます。すべてのクエリは、可能な限り最も効率的なクエリを生成する目的で使用できます。

この場合、必要なものをカバーするインデックスがあると思いますが、製品名はカバーしていません。それをwhere句に追加すると、インデックスは使用されず、代わりにスキャンが行われます。両方の条件が同時にテストされるため、エラーが発生します。

これは実際には結合条件のエラーです。数値であることが確実でない限り、to_numberを使用しないでください。

于 2012-04-10T15:12:22.267 に答える
0

to_number(p.product_value)有効な行にのみ適用されると思いますproduct_name

何が起こるかというと、あなたの句のjoin前にあなたが適用さwhereれ、その結果、関数が失敗しto_numberます。

あなたがする必要があるのは、次のような句としてあなたproduct_name like '%prototype%'を含めることです:JOIN

select * from
(select product, product_name from products p
join product_serial ps on product.id = ps.id
join product_data pd on product_name like '%prototype%' AND
     pd.product_value = to_number(p.product_value));
于 2012-04-10T15:04:49.590 に答える
0

より多くの背景(そして本当に良い読み物)については、JonathanGennickのSubqueryMadnessを読むことをお勧めします

基本的に、問題は、Oracleが任意の順序で述語を自由に評価できることです。product_nameしたがって、述語をサブクエリに自由にプッシュ(またはプッシュしない)できます。結合条件は任意の順序で自由に評価できます。したがって、Oracleがクエリプランを選択して、product_valueを適用する前に数値以外の行を除外したto_number場合、クエリは成功します。to_number数値以外の行を除外する前に、それが適用されるプランを選択した場合product_value、エラーが発生します。もちろん、最初のN行が正常に返され、行N + 1がto_number述語を適用しようとするのは初めてであるため、行N+1をフェッチしようとするとエラーが発生する可能性もあります。非数値データ。

データモデルを修正する以外に、クエリにいくつかのヒントをスローして、to_number述語が適用される前にすべての非数値データが除外されることを保証する述語をOracleに評価させることができます。しかし、一般的に、オプティマイザーが常に「適切な」順序で物事を評価するように強制するような方法でクエリを完全に示唆することは少し難しいです。

于 2012-04-10T15:22:40.923 に答える