1

演算子DETERMINISTICの右側で関数を使用すると、Oracle の実行計画が大混乱を引き起こします。LIKEこれは私の状況です:

状況

次のようなクエリを実行するのが賢明だと思いました(簡略化):

SELECT [...]
FROM customers cust
JOIN addresses addr ON addr.cust_id = cust.id
WHERE special_char_filter(cust.surname) like special_char_filter(?)

?そして、私はのようなものにバインドします'Eder%'。現在customersaddresses非常に大きなテーブルです。そのため、インデックスを使用することが重要です。もちろん、通常のインデックスがありaddresses.cust_idます。しかし、関数ベースのインデックスも作成しましたspecial_char_filter(customers.surname)。これは非常にうまく機能します。

トラブル

問題は、like句を含む上記のクエリが FULL TABLE SCANS on で実行プランを作成することaddressesです。このクエリの何かが、Oracle が でインデックスを使用できないようにしているようですaddresses.cust_id

回避策

私の問題の解決策は次のとおりであることがわかりました。

SELECT [...]
FROM customers cust
JOIN addresses addr ON addr.cust_id = cust.id
WHERE special_char_filter(cust.surname) like ?

DETERMINISTIClike 演算子の右側から( !) 関数を削除し、バインド変数を Java で事前に計算しました。現在、このクエリは超高速で、FULL TABLE SCANS はありません。これも非常に高速です (同等ではありませんが)。

SELECT [...]
FROM customers cust
JOIN addresses addr ON addr.cust_id = cust.id
WHERE special_char_filter(cust.surname) = special_char_filter(?)

混乱

私はこれを理解していません。like演算子の右側に決定論的関数があることの何が問題になっていますか? 私はこれをOracle 11.2.0.1.0で観察しました

4

3 に答える 3

2

問題は、Oracleが「special_char_filter(?)」が何を返すかを知らないことです。'%'を返す場合、すべてが一致するため、インデックスの使用は非常に遅くなります。'A%'を返す場合は、(すべての文字に均等に分散していると仮定して)行の約4%が一致するため、おそらく低速になります。'%FRED%'を返す場合、多くの行は返されませんが、行がインデックスの開始、中間、または終了にある可能性があるため、インデックス範囲スキャンを使用するとパフォーマンスが低下します。インデックス全体を実行します。

special_char_filterが、先頭に少なくとも3つの「実線」文字を含む文字列を常に返すことがわかっている場合は、おそらく幸運があります。

SELECT [...] FROM CustomerscustJOINアドレスaddrONaddr.cust_id = cust.id WHERE special_char_filter(cust.surname)like special_char_filter(?)AND substr(special_char_filter(cust.surname)、1,3)= substr(special_char_filter (?)、1,3)

substr(special_char_filter(cust.surname)、1,3)にFBIを使用

ただし、Javaで結果を事前に計算する場合は、それを使用してください。

それとは別に、私はおそらくOracleTextで一致するものを探すでしょう。

于 2011-03-17T23:12:59.327 に答える
2

クエリには何もない可能性があります。コストベースのオプティマイザーは混乱して、FULL TABLE SCAN の方が速いと考えるかもしれません。クエリで HINT を使用して、Oracle にインデックスを使用させようとしたことがありますか?

于 2011-03-17T16:19:16.870 に答える