2015-04-29 223 views
2

我注意到有兩種方法可以在多個表上實現一個目標。結果集中的列將被更新並且速度可能是需求。結果集獲得或者通過:在連接的列上連接多個列與單個連接的條件?

情況1:

select ert.* 
from eval_rep_track ert 
inner join 
(
     select erp.evaluation_fk, erp.report_type, LTRIM(erp.assign_group_id, '/site/') course_name 
     from [email protected] erp 
     inner join eval_report er 
     on er.id = erp.id 
     where erp.status='queue' 
     and er.status='done' 
) cat 

on ert.eval_id || '.' || ert.report_type || '.' || ert.course_name = cat.evaluation_fk || '.' || cat.report_type || '.' || cat.course_name; 

OR

情況2:

select ert.* 
from eval_rep_track ert 
inner join 
(
     select erp.evaluation_fk, erp.report_type, LTRIM(erp.assign_group_id, '/site/') course_name 
     from [email protected] erp 
     inner join eval_report er 
     on er.id = erp.id 
     where erp.status='queue' 
     and er.status='done' 
) cat 
on ert.eval_id = cat.evaluation_fk 
and ert.report_type = cat.report_type 
and ert.course_name = cat.course_name; 

既給出相同的結果,與僅連接條件而變化。哪個會更快運行/ exec?

eval_id是NUMBER,report_type和course_name是VARCHAR2

從使用的開發人員,情況1具有以下統計信息:[SELECT - 3077行,0.048秒]獲取結果集 ... 1個語句執行,3077行受影響,exec /讀取時間:0.048/0.236秒[1次成功,0次警告,0次錯誤]

while case 2:[SELECT - 3077 row,s0,0.019 secs]取出結果集 ... 1 statement(s) 3077行受到影響,執行/讀取時間:0.019/0.194秒[1次成功,0次警告,0次錯誤]

結果表明案例2更快。這是否會在任何平臺(IDE,開發人員)和數據庫中通用?這是依賴於數據類型還是串聯總是很昂貴?我實際上並不需要連接的結果。謝謝。

+0

帶連接的版本無法利用索引來優化連接。 – Barmar

回答

3

我認爲帶連接的版本實際上總是比較慢。

如果您正在比較的任何列都有索引,數據庫通常可以使用索引來優化聯接。在比較連接時,必須執行全表掃描,因爲計算結果不在索引中。

即使列未被索引,數據庫仍然可以更有效地執行比較。它一次比較一對列,並且只要其中一個比較失敗就會停止。在使用連接時,必須先將兩行中的所有列組合起來,然後進行字符串比較。

最後,如果任何列是數字的,則連接需要將數字轉換爲字符串的附加步驟。

0

它取決於表上的索引。通常,索引是使用列列表定義的,但不能與列連接(作爲表達式)一起定義,因此按照經驗法則,第二個版本的索引編制速度更快。

也就是說,dba可能(無論出於什麼原因,可能是中毒或精神錯亂)決定在列的連接上創建索引。在這種情況下,聲明的第一個版本可以使用索引,而不使用第二個版本。

+0

感謝@ammoQ的洞察力。另一篇文章給出了堅定的理由,阻止連接在某些情況下是不正確的。 – paxmemento

3

很簡單,加入各個欄目是正確的。加入級聯值不正確。與任何性能討論分開,你應該寫出正確的代碼。

對於任何特定的查詢,您可以使用連接編寫大多數正確的查詢。但是當你得到你不希望的數據時,你幾乎肯定會引入一些微妙的錯誤,這些錯誤會咬你。在這種情況下,只要列中包含句點,就可能會錯誤地匹配數據('a.b' || '.' || null = 'a' || '.' || 'b.')。在其他情況下,您還會遇到其他一些細微問題 - 日期和數字可能會隱式轉換爲字符串,使用不同的會話級別設置,可能會產生不同的結果(您的NLS_DATE_FORMAT可能包含時間組件,或者它可能不包含您的連接值或者可能不包括時間的比較)。如果您通常連接列,那麼最終會出現許多基於表中數據和執行代碼的用戶具有非常微妙的錯誤的查詢。從維護和支持的角度來看這很糟糕。性能應該至多是次要的問題。

從性能角度來看,正確的連接幾乎可以肯定會超越連接方式。當您正確連接時,優化程序可以在生成查詢計劃時考慮作爲連接一部分的各個列上的普通索引。如果您將值連接起來,Oracle最多可以對正常索引進行全面掃描,以獲取需要連接在一起的所有數據。但是這可能效率要低得多(特別是當你有超過幾千行時)。

從理論上講,連接方法對於某個查詢某個地方會更有效嗎?當然。一個虐待開發者可能會在連接結果上創建一個基於函數的索引,避免在各個列上創建索引,並生成一個連接方法更有效的測試用例。但是,通過在基本列上創建適當的相應索引(或索引),可以很容易地進行補救。對於某些查詢,連接可能會更有效,因爲它會阻止優化器使用它原本想要使用的索引嗎?當然。但是,這幾乎可以肯定地表明,您在優化程序設置或統計信息方面存在問題,應該解決該問題,而不是在該問題上使用創可貼。

+0

謝謝@Justin,特別是在串聯可能不正確的情況下。 – paxmemento