2016-06-13 136 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

不客气。是。这也是我第一次感兴趣。 –