2013-05-06 71 views
3

我有兩個級別的過濾我需要做一些相關的數據。第一個查詢看起來像:MySQL IN子句使用子選擇與值列表

SELECT t1.fk_id 
FROM t1 
LEFT JOIN t3 ON t3.fk_id = t1.fk_id 
WHERE t1.field1 > 10 AND t3.field2 = Y 

第二運行查詢與同fk_id領域的另一個表中,看起來像

SELECT t2.fk_id, SUM(t2.field3) AS sum_3, SUM(t2.field_4) AS sum_4 
FROM t2 
WHERE fk_id IN (fk_values_from_query_1) 
GROUP BY t2.fk_id 
HAVING sum_3 > 1000 

現在,我可以運行此兩種不同的方式,從什麼我可以說 - 雖然我沒有被綁定到任何一種方法,也沒有其他方法。我可以將第一個查詢作爲一個SUB-SELECT嵌入到第二個查詢中,從性能的角度來看,我知道這是非常糟糕的。或者,我可以從查詢1的結果中提取值,並將它們作爲查詢2中的列表(在我的應用程序代碼中)嵌入。

兩個部分對這個問題是:

  1. 是否有任何差異,性能明智的,上述2層查詢結構之間?
  2. 有沒有更好的方法來構造這2個查詢?

基準

我沒有完全測試,但跑我的版本,並通過Barmar發佈的版本,對我的數據。我的查詢在大約4.23秒內運行,而Barmar的版本只運行了0.60秒。這是一個85%的改善!

+0

記住性能最好,唯一的答案是:**基準**。您操作的數據類型,MySQL配置以及您所在硬件的屬性,它們將對任何查詢的性能產生巨大影響。 – tadman 2013-05-06 17:27:34

+0

絕對!但我對這些查詢的理論知之甚少,無法知道哪些方法「已知」效率低下。由於我們的數據庫沒有經過微調,所以「標準理論」可能會涵蓋我的案例。 – Elie 2013-05-06 17:31:12

+0

如果您關心速度,則需要進行基準測試。我試過的表面上看起來很荒謬的事情,只是十種不同方法中的一種,但它以某種方式大大超越了所有其他方法。 MySQL是一個不可預知的野獸。如果這兩種方法都能產生正確的數據,下一步就是在可能的情況下根據實際生產數據進行測試,或者儘可能使用真實的傳真。 – tadman 2013-05-06 17:41:28

回答

3

你應該使用JOIN將它們結合起來:

SELECT t2.fk_id, SUM(t2.field3) AS sum_3, SUM(t2.field_4) AS sum_4 
FROM t2 
JOIN (SELECT distinct t1.fk_id 
     FROM t1 
     JOIN t2 ON t3.fk_id = t1.fk_id 
     WHERE t1.field1 > 10 AND t3.field2 = 'Y') t4 
ON t2.fk_id = t4.fk_id 
GROUP BY t2.fk_id 
HAVING sum_3 > 1000 

我一直髮現的MySQL相比類似的加入對WHERE col IN (subquery)查詢可怕的執行。我沒有將它與查詢替換爲子查詢中的值進行比較,因爲我只在無法在單個查詢中執行此操作(例如,我需要匹配不同服務器上的數據)時才這樣做。

順便說一句,如果您還要過濾正在連接的表中的值,則無需使用LEFT JOIN

在所有情況下,請確保您在連接或IN子句中使用的密鑰上有索引。

+0

感謝您的額外方法。並且您對JOIN的評論很好。 – Elie 2013-05-06 17:44:57

+0

有時甚至可以在where子句中添加字段以增加效果。但是,如果您的t3.field2可能只有兩個值'Y'或'N',將其添加到索引中將毫無意義。但有時在某些RDBMS /情況下,這可能會提高索引被使用的機會。 – Nabheet 2013-05-06 18:09:02

+2

對,你通常只需要列上的索引來顯着減少行數。一個Y/N字段可能會將行數減半,這沒有多大幫助。不過,將它作爲組合索引的一部分可能很有用。 – Barmar 2013-05-06 18:11:19