2016-06-13 179 views
4

擁有這些表:優化MySQL查詢刪除子查詢

customers 
--------------------- 
`id` smallint(5) unsigned NOT NULL auto_increment, 
`name` varchar(100) collate utf8_unicode_ci default NOT NULL, 
.... 

customers_subaccounts 
------------------------- 
`companies_id` mediumint(8) unsigned NOT NULL, 
`customers_id` mediumint(8) unsigned NOT NULL, 
`subaccount` int(10) unsigned NOT NULL 

我需要得到誰被分配一個以上的子賬戶在同一家公司的所有客戶。

這是我的本錢:

SELECT * FROM customers 
WHERE id IN 
    (SELECT customers_id 
    FROM customers_subaccounts 
    GROUP BY customers_id, companies_id 
    HAVING COUNT(subaccount) > 1) 

該查詢太慢,雖然。如果我在子查詢的SELECT中添加DISTINCT修飾符到customers_id,它最終會爲整個查詢檢索相同的客戶列表。也許有沒有subquerying更好的方法,更快的事情會有所幫助,我不確定它是否會檢索一個準確的正確列表。

任何幫助?

+0

我認爲這是您的「COUNT」,需要太多時間。 'WHERE .. IN'也很慢,但你可以通過使用'LEFT JOIN'來改善它。 – Hearner

+0

@Hearner感謝您的建議。是的,我知道這一點。這實際上是由於子查詢。 – user3514092

回答

4

您可以用INNER JOIN替換子查詢:

SELECT t1.id 
FROM customers t1 
INNER JOIN 
(
    SELECT DISTINCT customers_id 
    FROM customers_subaccounts 
    GROUP BY customers_id, companies_id 
    HAVING COUNT(*) > 1 
) t2 
    ON t1.id = t2.customers_id 
+1

你的建議是更快的一個(約0.023秒沒有緩存)。謝謝你的幫助。 – user3514092

1

嘗試以下;)

SELECT DISTINCT t1.* 
FROM customers t1 
INNER JOIN customers_subaccounts t2 ON t1.id = t2.customers_id 
GROUP BY t1.id, t1.name, t2.companies_id 
HAVING COUNT(t2.subaccount) > 1 

你也可以在customers_id添加index

+0

我收到此錯誤:在子句中的列'subaccount'不明確 – user3514092

+0

已更新。請再次檢查。 – Blank

+0

嗯,它很慢(花了我42.74秒),它檢索重複的客戶。 – user3514092

2

您也可以嘗試使用EXISTS()這可能會更快然後加入:

SELECT * FROM customers t 
WHERE EXISTS(SELECT 1 FROM customers_subaccounts s 
      WHERE s.customers_id = t.id 
      GROUP BY s.customers_id, s.companies_id 
      HAVING COUNT(subaccount) > 1) 

你也應該考慮增加以下指標(如果不是還不存在):

customers_subaccounts (customers_id,companies_id,subaccount) 
customers (id) 
+0

你的查詢太慢了。無論如何感謝您的幫助。 – user3514092

2

假設你想要公司不同子帳戶(或者他們保證是不同的),那麼在某些情況下可能會更快:

select c.* 
from (select distinct cs.customers_id 
     from customers_subaccounts cs join 
      customers_subaccounts cs2 
      on cs.customers_id = cs2.customers_id and 
       cs.companies_id = cs2.companies_id and 
       cs.subaccount < cs2.subaccount 
    ) cc join 
    customers c 
    on c.customers_id = cc.customers_id; 

特別是,這可以利用customers_subaccounts(customers_id, companies_id, subaccount)上的索引。

注意:這假定subaccounts對於所需的行是不同的。真正需要的是在customers_subaccounts表中定義唯一行的方法。

+0

我試過了,它絕對比我的快得多。但是你必須糾正最後一行,我認爲這應該是** c.id = cc.customers_id **。它檢索與我的結果相同的結果,速度更快。 – user3514092

+0

我檢查過它的速度不如Tim Biegeleisen的建議。您的持續時間約爲0.043秒 – user3514092

+0

@ user3514092。 。 。我假設你有性能比較的陳述指數。蒂姆的回答也是一個非常好的答案(我在回答之前提出了這個答案)。在某些情況下,這可能會更快,因爲它不需要兩個級別的聚合。 –

1

有一種方法可以通過緩存子查詢結果來加快查詢速度。一個簡單的變化,在您的查詢意識的MySQL可以緩存子查詢結果:

SELECT * FROM customers 
WHERE id IN 
    (select * from 
    (SELECT distinct customers_id 
    FROM customers_subaccounts 
    GROUP BY customers_id, companies_id 
    HAVING COUNT(subaccount) > 1) t1); 

我很多年前使用它,它非常幫助我。

+0

你的意思是把一個三級子查詢作爲別名,它會緩存結果?這很有趣,因爲它與我的查詢非常相似。我試過了,速度非常快(大約0.027秒)。 – user3514092

+0

不客氣。是。這也是我第一次感興趣。 –