优化MySQL查询删除子查询

优化MySQL查询删除子查询,mysql,sql,Mysql,Sql,有以下表格: 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 NUL

有以下表格:

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中向customers\u id添加DISTINCT修饰符,那么速度会更慢,它最终会为整个查询检索相同的customers列表。也许没有子查询有更好的方法,任何更快的方法都会有帮助,我不确定它是否能检索到准确的列表


有什么帮助吗?

您可以用内部联接替换子查询:

试着跟随

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
您还可以在客户id上添加索引。

您还可以尝试使用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)
假设您希望公司有不同的子帐户,或者保证它们无论如何都是不同的,那么在某些情况下,以下操作可能会更快:

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;
特别是,这可以利用客户子帐户、客户id、公司id、子帐户的索引


注意:这假定所需行的子帐户不同。真正需要的是在customers\u subaccounts表中定义唯一行的方法。

有一种方法可以通过缓存子查询结果来加快查询速度。支持查询的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);

很多年前我就用过它,它对我很有帮助。

我认为是你的计算花费了太多的时间。在哪里。。IN也很慢,但您可以通过使用左连接来改进它。@Hearner感谢您的建议。是的,我知道。实际上是因为子查询。我试过了,它肯定比我的快得多。但是你必须纠正最后一行,我认为应该在c.id=cc.customers\u id上。它检索的结果与我的相同,而且更快。我检查过它没有Tim Biegeleisen建议的那么快。你的持续时间大约是0.043秒secs@user3514092 . . . 我假设您有用于性能比较的指定索引。蒂姆的答案也是一个很好的答案,我在回答之前投了赞成票。在某些情况下,这可能更快,因为它不需要两级聚合。您的查询也太慢。无论如何谢谢你的帮助。我得到了这个错误:having子句中的'subaccount'列是含糊不清的更新。请再次检查。嗯,这很慢,花了我42.74秒,它检索到了重复的客户。如果像我更新的答案那样使用内部连接呢@user3514092您的建议是在不使用缓存的情况下,在0.023秒左右更快的建议。谢谢您的帮助。您的意思是将第三级子查询作为别名封装,它将缓存结果?这很有趣,因为它仍然非常类似于我的查询。我试过了,速度非常快,大约0.027秒。不客气。对第一次对我来说也很有趣。
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);