微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用COUNT的子查询使MYSQL查询变慢

如何解决使用COUNT的子查询使MYSQL查询变慢

| 是的,我不知道为什么,但是此查询需要花费6秒钟以上的时间来执行,索引都已正确设置,如果我分别运行每个查询,它只需不到0.5秒钟的时间就可以很好地工作。 这是查询
SELECT c.supplier_id,supplier_name,address1,address2,address3,address4,suppliertype,postcode,contact_name,(SELECT COUNT(*)
    FROM supplier_questions q1
    WHERE c.supplier_id = q1.supplier_id AND q1.incomplete = \'0\') AS questions,IF (active=1,\'Yes\',IF (active=2,\'NCR Only\',\'Inactive\')) AS rated,(SELECT COUNT(*)
    FROM supplier_questions q2
    WHERE c.supplier_id = q2.supplier_id AND q2.reviewed = \'1\') AS reviewed,questapproved,ss.supplier_no AS supplier_no
FROM suppliers c
INNER JOIN supplier_site ss ON c.supplier_id = ss.supplier_id
WHERE c.supplier_id != \'0\' AND ss.site_id = \'2\'
GROUP BY c.supplier_id
ORDER BY c.supplier_name ASC
LIMIT 0,20
Explain查询的结果如下
id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY ss  ref site_id,supplier_id site_id 4   const   1287    Using where; Using temporary; Using filesort
1   PRIMARY c   eq_ref  PRIMARY PRIMARY 4   ss.supplier_id  1   
3   DEPENDENT SUBQUERY  q2  ref supplier_id,reviewed    reviewed    4   const   263 Using where
2   DEPENDENT SUBQUERY  q1  ref supplier_id,incomplete  incomplete  4   const   254 Using where
计数查询存在的原因是因为我需要知道那些表中的行数,这不能在另一个查询中完成,因为结果还需要按这些值进行排序:(     

解决方法

作为暗中的一击,这运行得更快吗? (我没有mysql来验证语法,因此可以原谅任何细微的错误,但您可能会明白)
SELECT c.supplier_id,supplier_name,address1,address2,address3,address4,suppliertype,postcode,contact_name,questions,reviewed 
IF (active=1,\'Yes\',IF (active=2,\'NCR Only\',\'Inactive\')) AS rated,questapproved,ss.supplier_no AS supplier_no 
FROM suppliers c 
INNER JOIN supplier_site ss ON c.supplier_id = ss.supplier_id 
inner join 
(SELECT supplier_id,sum(if(incomplete=\'0\',1,0)) as questions,sum(if(incomplete=\'1\',0)) as reviewed FROM supplier_questions q1 group by supplier_id) as tmp
on c.supplier_id = tmp.supplier_id
WHERE c.supplier_id != \'0\' AND ss.site_id = \'2\' 
GROUP BY c.supplier_id 
ORDER BY c.supplier_name ASC LIMIT 0,20 
    ,
FROM suppliers c
INNER JOIN supplier_site ss ON c.supplier_id = ss.supplier_id
WHERE c.supplier_id != \'0\' AND ss.site_id = \'2\'
GROUP BY c.supplier_id 
ORDER BY c.supplier_name ASC
由于自动生成的主键永远不会等于0(除非出现大的数据库设计错误),所以可以删除c.supplier_id!= \'0 \'子句。 ss.site_id = \'2 \'应该处于JOIN条件以提高可读性。 看起来这应该只与每个供应商的表Supplier_site中的一行匹配(如果这是您通常的1-N物-地址关系,即您正在选择每个供应商的第二个地址,则\'2 \'对应于\ '帐单地址\”之类的东西,因此GROUP BY c.supplier_id是无用的。如果GROUP BY实际执行了某项操作,则该查询是错误的,因为“ address \”列(可能来自于vendor_site表)将来自随机行。 所以这是简化的FROM(WHERE不在了):
FROM suppliers c
INNER JOIN supplier_site ss ON 
    (c.supplier_id = ss.supplier_id AND ss.site_id = \'2\')
ORDER BY c.supplier_name ASC
我想您在c.supplier_name上有一个索引,因此查询的这一部分应该非常快。 现在尝试以下查询:
SELECT a.*,ss.supplier_no AS supplier_no,IF (active=1,sum( q.incomplete = \'0\') AS questions,sum( q.reviewed = \'1\' ) AS reviewed
FROM
(
    SELECT c.supplier_id,contact_name
    FROM suppliers c
    INNER JOIN supplier_site ss ON 
        (c.supplier_id = ss.supplier_id AND ss.site_id = \'2\')
    ORDER BY c.supplier_name ASC
    LIMIT 0,20
) a
LEFT JOIN supplier_questions q ON (q.supplier_id = c.supplier_id)
GROUP BY c.supplier_id
ORDER BY c.supplier_name;
    ,如果删除子选择,则结果如下:
SELECT c.supplier_id,COUNT(IF (q1.incomplete = \'0\',\'0\',null)) AS questions,COUNT(IF (q1.reviewed = \'1\',\'1\',null)) AS reviewed,ss.supplier_no AS supplier_no
FROM suppliers c
INNER JOIN supplier_site ss ON c.supplier_id = ss.supplier_id
LEFT OUTER JOIN supplier_questions q1 ON c.supplier_id = q1.supplier_id
WHERE c.supplier_id != \'0\' AND ss.site_id = \'2\'
GROUP BY c.supplier_id
ORDER BY c.supplier_name ASC
LIMIT 0,20
我没有可用的MySQL数据库,因此SQL可能有错误。 这个想法是删除子查询并用外部联接替换它们 并使用IF仅计算相关行。     ,我将首先尝试通过按供应商预先查询汇总的问题计数并审查一次ONCE来进行重组。然后,加入其余的细节。通过使用STRAIGHT_JOIN关键字,它应该按照显示的顺序进行处理。这将首先进行预汇总,并以THAT为基础加入供应商,然后再加入供应商地点。不需要外部组,因为它无论如何都是基于供应商ID的。但是,如果连接到vendor_sites(您的ss.supplier_no),则意味着供应商具有多个位置。这是否意味着地址和活动状态列源自该表? 问题的加入是否应与特定的供应商及其对应的站点位置相关联? 此外,由于预查询在Supplier_id!= \'0 \'上具有WHERE子句,因此不需要下游,因为这将成为正常连接其他表的基础,从而将它们从结果集中删除。
SELECT STRAIGHT_JOIN
      PreAggregate.supplier_id,PreAggregate.supplier_name,PreAggregate.Questions,PreAggregate.Reviewed,ss.supplier_no AS supplier_no
   FROM 
      (select 
             s1.Supplier_ID,s1.Supplier_Name,SUM( IF( q1.Incomplete = \'0\',0 )) Questions,SUM( IF( q1.Reviewed = \'1\',0 )) Reviewed
          from 
             suppliers s1
                join supplier_questions q1
                   ON s1.supplier_id = q1.supplier_id
          where
             s1.supplier_id != \'0\'
          group by
             s1.Supplier_ID 
          ORDER BY 
             s1.supplier_name ASC ) PreAggregate

       JOIN suppliers c
          ON PreAggregate.Supplier_ID = c.Supplier_ID

       JOIN supplier_site ss 
          ON PreAggregate.Supplier_ID = ss.supplier_id
          AND ss.Site_ID = \'2\'
  LIMIT 0,20
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。