2015-02-11 71 views
0

我有這種形式的MySQL查詢:SELECT中的子查詢或JOIN中的子查詢?

SELECT 
    employee.name, 
    totalpayments.totalpaid 
FROM 
    employee 
    JOIN (
     SELECT 
      paychecks.employee_id, 
      SUM(paychecks.amount) totalpaid 
     FROM 
      paychecks 
     GROUP BY 
      paychecks.employee_id 
     ) totalpayments on totalpayments.employee_id = employee.id 

我最近發現,它返回快得多這種形式:

SELECT 
    employee.name, 
    (
     SELECT 
      SUM(paychecks.amount) 
     FROM 
      paychecks 
     WHERE 
      paychecks.employee_id = employee.id 
    ) totalpaid 
FROM 
    employee 

我很驚訝會有的速度差,並且較低的查詢會更快。我更喜歡開發的上層表單,因爲我可以獨立運行子查詢。

有沒有辦法獲得「兩全其美」:快速結果返回並能夠獨立運行子查詢?

回答

0

有可能的,相關子查詢能夠有效地利用索引,這就是爲什麼它的快速,即使該子查詢必須被執行多次的。

對於帶內聯視圖的第一個查詢,導致MySQL創建派生表,對於大集合,這實際上是MyISAM表。

在MySQL 5.6.x及更高版本中,優化程序可能會選擇在派生表上添加索引,如果這允許執行ref操作並且ref操作的估計成本低於嵌套循環掃描。

我建議您嘗試使用EXPLAIN來查看訪問計劃。 (根據你的業績報告,我懷疑你是在MySQL 5.5版運行或更早)。


這兩種說法並不完全等同,在那裏有在employees行的情況下對其中有沒有匹配paychecks中的行。

的等效結果可以完全獲得避免子查詢:

SELECT e.name 
    , SUM(p.amount) AS total_paid 
    FROM employee e 
    JOIN paychecks p 
    ON p.employee_id = e.id 
GROUP BY e.id 

(使用一個內連接以獲得等同於所述第一查詢的結果,使用一個LEFT外部聯接以等同於所述第二查詢。如果要在工資中找不到與空值爲amount的匹配行時返回0而不是NULL值,則將SUM()聚合包括在IFNULL函數中。)

+0

非常感謝,spencer7593!我可以嘗試在派生表上強制索引嗎? (我不太熟悉索引或創建它們的語法。) – 2015-02-11 17:26:40

+0

@YossiFendel:我不相信在派生表上創建索引有任何提示。這隻會在版本5.6和更高版本中發生。 EXPLAIN輸出應顯示正在使用哪種連接操作。通過完全避免子查詢可能獲得最佳性能。我在編輯答案時提供了一個示例。 – spencer7593 2015-02-11 17:31:42

+0

@YossiFendel:另一個選項是創建一個臨時表(帶索引)作爲子查詢的結果,然後在第二個查詢中引用該臨時表。這很麻煩,但它可以提高性能,特別是當多個查詢中引用相同的內聯視圖時......因爲我們避免了多次實現它。 – spencer7593 2015-02-11 17:36:42

0

加入基本上是笛卡爾產品那mea ns表A的所有記錄將與表B的所有記錄相結合的輸出將是

number of records of table A * number of records of table b =rows in the new table 
10 * 10 = 100 

進出的100條記錄,符合過濾器的那些會在查詢返回。

在嵌套查詢中,有一個示例內部查詢,並且無論內部查詢的記錄的總大小是outter查詢的輸入,這就是爲什麼嵌套查詢比連接速度更快的原因。

+0

是的,有時,SELECT列表中的相關子查詢比聯接操作更快,但通常情況並非如此。對創建笛卡爾乘積(m * n行),然後過濾出行的連接操作的描述並不是對JOIN操作實際操作方式的完全準確描述。要真正得到你描述的行爲,你需要寫一些能夠創建笛卡爾積的東西,例如:'SELECT a.id,b.id FROM a JOIN b HAVING a.id = b.id'。但是,在WHERE子句或ON子句中使用連接謂詞時,就不會發生。 – spencer7593 2015-02-11 17:43:51