2008-10-07 84 views
0

我剛剛發現,甲骨文可以讓你做到以下幾點:Oracle中的單行子查詢 - 連接計劃是什麼?

SELECT foo.a, (SELECT c 
       FROM bar 
       WHERE foo.a = bar.a) 
from foo 

只要在酒吧只有一排中的任何行FOO匹配。

解釋計劃,我從PL/SQL開發人員得到的是:

SELECT STATEMENT, GOAL = ALL_ROWS    
TABLE ACCESS FULL BAR 
TABLE ACCESS FULL FOO 

這實際上並不指定如何聯接表。一位同事斷言,這比定期加入更有效。真的嗎?這種選擇語句的連接策略是什麼?爲什麼它沒有出現在解釋計劃中?

謝謝。

回答

4

你在那裏的計劃根本沒有提供太多的信息。

使用SQL * Plus並使用dbms_xplan獲取更詳細的計劃。尋找名爲utlxpls.sql的腳本。

這給了更多的信息: -

-------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  | 1837 | 23881 |  3 (0)| 00:00:01 | 
|* 1 | TABLE ACCESS FULL| BAR | 18 | 468 |  2 (0)| 00:00:01 | 
| 2 | TABLE ACCESS FULL| FOO | 1837 | 23881 |  3 (0)| 00:00:01 | 
-------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("BAR"."A"=:B1) 

Note 
----- 
    - dynamic sampling used for this statement 

18 rows selected. 

我沒有創建任何索引或外鍵或收集表,這將改變計劃和加入機制choosen統計。 Oracle實際上正在做一個NESTED LOOPS類型的連接。對於從FOO返回的每一行執行第一步,您的內聯子選擇。

這種執行SELECT的方法並不快。它可能相同或更慢。通常在WHERE子句中嘗試並加入所有內容,除非它變得非常難以理解。

+0

謝謝,這就是我懷疑的。但爲什麼嵌套循環沒有出現在計劃中?我同意這是一種倒退的做法,而且讓我們驚訝的是,Oracle甚至可以讓你寫這樣的東西。但是我必須檢查效率要求。 – SquareCog 2008-10-07 21:57:25

2

如果你在bar(a)上創建了一個正常的索引,CBO應該可以使用,但是我敢肯定它不能做hash連接。這些查詢只有在使用聚合函數時纔有意義,並且在頂級SELECT中有多個單行子查詢。即便如此,你總是可以重寫查詢爲:

SELECT foo.a, bar1.c, pub1.d 
FROM foo 
JOIN (SELECT a, MIN(c) as c 
     FROM bar 
     GROUP BY a) bar1 
    ON foo.a = bar1.a 
JOIN (SELECT a, MAX(d) as d 
     FROM pub 
     GROUP BY a) pub1 
    ON foo.a = pub1.a 

這將使CBO使用更多的選擇,而在同一時間,它將使您能夠輕鬆地檢索子表的多個列,而無需掃描相同的表多次。