优化MySQL查询,从另一个表中选择行作为列并使用HAVING子句

时间:2016-07-27 17:50:39

标签: mysql

我正在试图弄清楚如何加速使用连接和分组的查询来从表中获取行作为另一个表中的列,并且还使用having子句。

我有以下两个表:

用户:

id  name
1   bob
2   joe
3   paul

财产:

id  user_id type_id type        name
1   1       1       car         honda
2   1       2       computer    mac
3   2       1       car         toyota
4   2       2       computer    pc
5   2       3       phone       htc
6   3       1       car         toyota
7   3       2       computer    pc
8   3       3       phone       samsung

我正在使用以下查询:

select
  p.user_id,
  u.name,
  max(case when p.type=1 then p.name end) as car,
  max(case when p.type=2 then p.name end) as computer,
  max(case when p.type=3 then p.name end) as phone
from
  possesions p inner join users u
  on p.user_id=u.id
group by
  p.user_id,
  u.name
having
  car='toyota'

将此作为输出:

user_id name    car     computer    phone
2       joe     toyota  pc          htc
3       paul    toyota  pc          samsung

有大量的数据 - 大约75,000个用户,20万个拥有者和25种不同的拥有类型。查询大约需要5秒钟。当我对查询做一个解释时,我得到了这个:

id  select_type table      type   possible_keys          key                    key_len    ref             rows     Extra
1   SIMPLE      users      index  (NULL)                 PRIMARY                4          (NULL)          77453    Using index
1   SIMPLE      possesions ref    FK_possessions_users   FK_possessions_users   4          mydb.users.id   1    

我在所有id列上都有索引。只是想知道我还能做些什么来加快速度。如果我删除HAVING子句,它当然会变得很快。非常感谢任何帮助,谢谢。

1 个答案:

答案 0 :(得分:0)

这是您的查询:

select u.id, u.name,
       max(case when p.type = 1 then p.name end) as car,
       max(case when p.type = 2 then p.name end) as computer,
       max(case when p.type = 3 then p.name end) as phone
from users u join
     possesions p
     on p.user_id = u.id
group by u.id, u.name
having car = 'toyota';

MySQL基本上没有提供优化聚合查询的机会。您可以将其更改为join版本以查看是否有效。因此,假设每种类型最多出现一次:

select u.id, u.name, pc.name as car, pcomp.name as computer, pp.name as phone
from users u join
     possesions pc
     on pc.user_id = u.id and
        pc.type = 1 and pc.name = 'toyota' left join
     possessions pcomp
     on pcomp.user_id = u.id and pcomp.type = 2 left join
     possessions pp
     on pp.user_id = u.id and pp.type = 3;

为此,您需要pc(user_id, type, name)上的索引。

注意:查询的节省是避免使用group by进行聚合。如果给定类型有多个名称,则无论如何都可能需要聚合。