2012-02-06 111 views
4

以下是查詢同樣的目的 兩個例子(在這個例子中,我想從那裏Patriks住同一個城市精細的推銷員。)哪個效率高?查詢與子查詢或連接表

select * 
from salesman 
where salesman.city = 
    (select city 
     from salesman 
     where salesman_name='Patriks' 
    ); 

select s1.* 
from salesman s1,salesman s2 
where s1.city=s2.city 
    and s2.salesman_name='Patriks'; 

哪個更好或更高效,爲什麼? (我知道這是一個小例子,但我想弄清楚,這對於複雜的情況以及對於大型數據庫來說是很好的。)

+1

http://stackoverflow.com/questions/2577174/join-vs-subquery – amd 2012-02-06 08:07:33

回答

5

作爲一個一般的經驗法則:

如果您使用子查詢,你迫使Oracle使用一定的執行路徑(即它必須執行的子查詢,纔可以執行外部查詢)

如果您使用連接,Oracle可以自由選擇它認爲最有效的路徑。

因此我會經常參加子查詢。因人而異。

+0

我不明白:**爲什麼**子查詢強制Oracle使用某個執行路徑?如果你不知道爲什麼,是什麼讓你認爲這通常是真的? – onedaywhen 2012-02-06 08:37:37

+2

因爲你不能在外部位上工作,直到你得到內部位的結果。 (作爲一個例子,想象它就像x =(5 *(4 + 2))。在你可以進行外部乘法之前,你必須先做內部(4 + 2)。)注意,優化器有可能能夠去解決內部/外部結構問題,但根據我的經驗,情況往往不是這樣。 – cagcowboy 2012-02-06 08:43:20

+0

保留你的類比,優化器應該能夠通過移除'內部'元素(即x =(5 * 4 + 5 * 2))來轉換它。 – onedaywhen 2012-02-06 10:03:09

5

我的經驗是,在Oracle中,扁平查詢(即,與連接相比)通常比使用子查詢的等效查詢更高效。看起來在更復雜的情況下,Oracle優化器找不到查詢路徑,對於使用子查詢的查詢。在SQL Server,DB2,Ingres和Sybase中,我的經驗是它沒有什麼區別 - 無論您是使用扁平化查詢還是帶有子選擇的查詢,這些DBMS都具有可找到相同查詢路徑的優化器。

我沒有足夠的其他DBMS經驗來評論這些。

但這只是我的經驗。如果您發現特定查詢或特定數據集的不同結果,我不會感到驚訝。最好的辦法是嘗試兩種方式,並根據自己的情況瞭解哪種查詢效果更好。

2

經驗,只要子查詢和JOIN 意味着同樣的事情,Oracle將執行它們同樣快。

人們經常重寫他們的疑問,並認爲他們一直保持等價,實際上他們引入了細微的差異。例如,OP的查詢是否意味着相同的事情取決於salesman_name是否是PRIMARY KEY(或UNIQUE)。如果不是,這些查詢不再意味着同樣的事情。這就是說,如果真的存在某些情況(如其他人所指出的那樣),那麼我並不會感到驚訝,因爲在這種情況下,Oracle實際上確實會產生大不相同的執行計劃。您的里程可能會有所不同,但一如既往 - 衡量有代表性的數據量,不要盲目地假設其中一方。

2

這個問題根本沒有答案。即使你的表結構沒有改變,查詢也可以隨着時間的推移獲得不同的執行路徑,這取決於數據量,索引,約束,綁定變量窺視,以及其他一些因素。整本書都是關於這個主題的。

cagcowboy的回答是不正確的。Oracle會重寫你的查詢來提供它認爲最好的執行計劃。像你描述的查詢經常被subquery unnesting轉換。我的猜測是10次中有9次,類似於你描述的查詢將具有相同的執行計劃。

在我看來,先從什麼是最可讀的,什麼會令它清晰的給別人讀你的代碼(或自己,閱讀它從現在起半年),你的目的是什麼。如果您的查詢運行速度慢得令人難以接受,請嘗試優化它。你認爲

正如布蘭科Dimitrijevic指出,這兩個查詢是相同的往往是不等價的。在你的兩個例子中,如果salesman_name不是唯一的,你的第一個查詢將拋出一個ORA-01427: single-row subquery returns more than one row異常,但你的第二個例子會正常工作。

+0

>沒有問題,它只是一個例子,如果它應該返回多行,我可以在''處使用'in'。 – Patriks 2012-02-08 04:49:27

+0

在某些情況下_sub-query_比加入表格更好, 一旦我遇到>何時,表格中有成千上萬的行,並且我使用查詢(作爲我的問題中的第二個),它需要大約一分鐘才能檢索數據,然後我用_sub-query_ type查詢替換它是很好的。 – Patriks 2012-02-08 04:56:41

+0

我認爲它會發生,因爲 '選擇S1 * 從推銷員S1,S2業務員那裏 = s1.city s2.city 和s2.salesman_name = 'Patriks';' 在這個例子中,SQL首先需要比較所有s1的行與s2的行一起查找要加入的匹配行。因此它需要以匹配X * X倍(X =沒有行的。) 和在 的情況下'SELECT * FROM推銷員 其中salesman.city = (從推銷員 其中salesman_name ='Patriks選擇城市 ' );' 它只需要將內側行與只有內行查詢返回的一行進行比較。所以在這種情況下,我發現sub_query更好 – Patriks 2012-02-08 04:57:28