2008-12-17 170 views
6

我的工作在別人的PHP代碼,並在看到這個模式和過:LEFT JOIN與多個SELECT語句

(僞)

result = SELECT blah1, blah2, foreign_key FROM foo WHERE key=bar 

if foreign_key > 0 
    other_result = SELECT something FROM foo2 WHERE key=foreign_key 
end 

代碼需要分支,如果沒有相關的行在另一個表中,但是通過在單個SELECT語句中執行LEFT JOIN可以做到這一點嗎?我錯過了一些性能優勢?可移植性問題?或者我只是挑剔?

+0

自1987年以來,我一直在使用SQL數據庫,但我從未接受過任何SQL課程。直到最近,我可能會以第一種方式做到這一點,因爲我不瞭解LEFT JOIN。 – 2008-12-17 23:21:02

+0

這個_really_需要九個以上的答案嗎? – Will 2008-12-17 23:29:30

+2

@會,你有什麼反對每個人把他們的帽子扔進答案環嗎?更好的答案越好,好的答案就會浮出水面。 – mmcdole 2008-12-18 01:38:21

回答

5

沒有足夠的信息來真正回答問題。由於某種原因,我減少查詢計數並增加查詢計數的原因是由於另一個原因這兩個都改善了性能。在同一個應用程序!

對於表的大小,數據庫配置和頻率的外部表將被查詢的某些組合,做兩個查詢可以更快比LEFT JOIN。 但經驗和測試是唯一會告訴你,。具有中等大表的MySQL似乎對此感到不可思議,IME。在一張桌子上執行三個查詢通常比一個查詢加入三個查詢快得多。我已經看到了一個數量級的加速。

3

我和你在一起 - 一個SQL會更好

2

有治療你的SQL數據庫管理系統,如果它是一個ISAM文件系統,在同一時間從一個單一的表中選擇的危險。在外連接中使用單個SELECT可能會更清晰。另一方面,在應用程序代碼中檢測到null並根據null與non-null決定做什麼也不是完全乾淨的。

單個語句的一個優點 - 您有更少的往返服務器 - 特別是如果每​​次需要其他結果時都動態準備SQL。

平均而言,單個SELECT語句更好。它爲優化器提供了一些東西,並將其保存得過於無聊。

+0

是的,我們必須保持優化者的滿意度! :-) – 2008-12-17 23:33:36

2

在我看來,那你的意思是相當有效的 - 爲什麼火了兩次調用數據庫時,一個會做 - (?),除非這兩個記錄都需要獨立的對象

當然同時可能並不是簡單的代碼明智的方式,將它從數據庫的一次調用中分離出來,並將這些字段分隔成兩個單獨的對象,這意味着您只依賴數據庫進行一次調用而不是兩次...

這將是更好的讀取,查詢:

Select a.blah1, a.blah2, b.something From foo a Left Join foo2 b On a.foreign_key = b.key Where a.Key = bar; 

這樣你就可以檢查你是否得到了一個結果,並讓數據庫在一個查詢中完成所有繁重的工作,而不是兩個...

是的,我認爲看起來好像你所說的是正確。

6

這是絕對錯誤的。你沒有理由再次通過電線。數據庫在他們的問題空間非常快。連接表就是其中之一,你會看到更多的性能從第二個查詢,然後是聯接。除非你的表空間有成千上萬的記錄,否則這不是一個好主意。

1

考慮到在一個數據庫命中中,您擁有所有需要的數據,而有一條SQL語句在99%的時間內性能會更好。不知道在這種情況下連接是否正在動態創建,但如果這樣做是昂貴的。即使過程如果重複使用現有連接,DBMS也沒有得到優化,查詢是最好的方式,而不是真正利用關係。

爲了性能的原因,我唯一能看到這樣的調用的唯一方法是,如果外鍵檢索的數據量很大,而且只在某些情況下需要。但是在你描述的樣本中,如果它存在,它就抓住它,所以情況並非如此,因此沒有獲得任何性能。

1

所有這一切的唯一「難題」是如果結果集合使用包含大量連接,甚至嵌套連接。

我現在有兩個或三個實例,其中原來的查詢是我繼承的,它由一個查詢組成,這個查詢有很多連接,並且需要SQL準備好語句。

我回到了程序,利用一些表變量(或臨時表),並打破了查詢分解成很多小單選擇類型語句和構造的最終結果以這種方式設置。

此更新顯着地將響應時間固定爲幾秒,因爲更容易執行大量簡單的「一次性」檢索必要的數據。

我並不想在這裏爲對象着想的反對,而只是指出該代碼可能已經被分解到這樣的粒度級別來解決類似的問題。

2

最可能的解釋是開發人員根本不知道外連接如何工作。這是非常普遍的,即使是在自己的專業經驗豐富的開發人員中也是如此。

還有一個普遍的說法是「加入查詢很慢」。許多開發人員不惜一切代價盲目避免連接,甚至在運行多個查詢的情況下也會更好。

避免的神話聯接好像是說我們應該避免在應用程序代碼的編寫循環,因爲運行的代碼行多次明顯高於一次運行更慢。不要在每次迭代期間對++i的「開銷」和測試i<20

1

單個SQL查詢將更多的表現爲SQL服務器(有時不共享相同的位置),導致只需要處理一個請求,如果你想使用多個SQL查詢,然後您介紹了很多的開銷:

執行更多的CPU指令, 發送第二查詢到服務器, 在服務器上創建第二個線程, 對服務器執行的可能更多的CPU指令 ,破壞服務器上的第二個線程 ,發第二次結果 回來。

可能會出現例外情況,表現可能會更好,但對於簡單的事情,您可以通過做更多的工作來達到更好的性能。

1

做一個簡單的兩個表連接通常是解決這個問題域的最好方法,但是根據表和索引的狀態,在某些情況下可能會更好地執行兩個select語句,但通常我還沒有碰到這個問題,直到我開始接近3-5連接的表,不只是2

只要確保你已經覆蓋兩個表的索引,以確保不會掃描磁盤的所有記錄,這是最大的性能打了一個數據庫中獲取(在我有限的經驗)

2

你是完全正確的,因爲單個查詢是要走的路。爲了給其他答案增加一些價值,讓我添加這個公理:「使用正確的工具來完成這項工作,數據庫服務器應該處理查詢工作,代碼應該處理程序性工作。」

這個概念背後的關鍵思想是,編譯器/查詢優化可以做一個更好的工作,如果他們知道整個問題域,而不是它的一半。

1

你應該總是儘量減少查詢數據庫的數量,當你可以。您的示例僅適用於1個查詢。這樣,您稍後可以更輕鬆地緩存或在同一時間處理更多請求,因爲不是總是使用2-3個需要連接的查詢,而是每次只有1個查詢。

1

有很多情況下,這將需要不同的解決方案,這是不可能的解釋都在一起。

加入掃描兩個表,並循環到匹配第二個表中的第一個表的記錄。在許多情況下,簡單選擇查詢的運行速度會更快,因爲它僅關注主鍵/唯一鍵(如果存在)以在內部搜索數據。