2012-04-10 46 views
5

愚蠢的問題時間。 Oracle 10g。影響加入的條款

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字段中包含非數字的行連接時,會發生「無效數字」錯誤。但是,我的問題是如何選擇這些行?如果連接成功,而沒有外部where子句,那麼不應該在外部where子句中只選擇連接結果中的行?看起來發生了什麼是where子句正在影響哪些行被連接,儘管連接處於內部查詢中。

我的問題有意義嗎?

+0

你可以給它一點點'to_char(pd.product_value)= p.product_value'。 – briantyler 2012-04-10 15:27:34

回答

1

簡答:是的。

長答案:只要它返回相同的結果,查詢引擎就可以自由地重寫您的查詢。所有查詢都可用於生成最有效的查詢。

在這種情況下,我猜想有一個索引涵蓋了你想要的東西,但它不包括產品名稱,當你將其添加到where子句時,索引不被使用,而是改爲有一個掃描在兩個條件同時進行測試,因此你的錯誤。

在連接條件中,這實際上是一個錯誤,除非您確定它是一個數字,否則不應該使用to_number。

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)); 
+0

這可能會也可能不會有幫助 - 沒有什麼能阻止Oracle首先嚐試評估「to_number」。 – 2012-04-11 01:38:05

2

它會影響系統產生的計劃。

表格加入(並過濾)的實際順序不是由您編寫查詢的順序決定的,而是由表格上的統計信息決定的。

在一個版本中,同時生成的計劃意味着「壞」行永遠不會被處理;因爲前面的連接會將結果集過濾到它們從未加入的位置。

WHERE子句的引入意味着ORACLE現在認爲不同的連接順序更好(因爲根據產品名稱進行篩選需要特定的索引,或者因爲它將數據縮小了很多,等等)。

這個新訂單意味着'壞'行在聯結過濾之前得到處理。


我會盡力查詢之前清理數據。可能通過創建派生列,其中值已經轉換爲數字,或者如果不可能,則保留爲NULL。

您還可以使用EXPLAIN PLAN查看正在查詢的不同計劃。

0

欲瞭解更多背景(和一個非常好的閱讀),我建議閱讀喬納森根尼克的Subquery Madness

基本上,問題是Oracle可以以任何順序自由評估謂詞。所以可以自由地將(或不推送)謂詞放入子查詢中。可以按任何順序評估連接條件。因此,如果Oracle恰好在應用to_number之前選擇了一個查詢計劃,並在其中篩選出非數字的product_value行,則查詢將會成功。如果碰巧在篩選出非數字product_value行之前選擇了應用to_number的計劃,則會出現錯誤。當然,它也有可能成功返回前N行,並且當您嘗試獲取第N + 1行時,您會收到錯誤,因爲第N + 1行是第一次嘗試應用to_number謂詞到非數字數據。

除修復數據模型外,您可能會向查詢中拋出一些提示,強制Oracle評估謂詞,以確保在應用to_number謂詞之前,所有非數字數據都被過濾掉。但總的來說,以一種強制優化器始終以「正確」順序評估事物的方式完全提示查詢是有點具有挑戰性的。