对,我不知道为什么但是这个查询执行时间超过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
计数查询所在的原因是因为我需要知道这些表中的行数,这不能在另一个查询中完成,因为结果也需要按这些值排序:(
答案 0 :(得分:2)
在黑暗中刺伤,这会跑得更快吗? (我没有一个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',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
答案 1 :(得分:2)
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实际上做了什么,那么查询是错误的,因为“地址”列(可能来自supplier_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.*,
questapproved,
ss.supplier_no AS supplier_no,
IF (active=1,'Yes', IF (active=2, 'NCR Only','Inactive')) AS rated,
sum( q.incomplete = '0') AS questions,
sum( q.reviewed = '1' ) AS reviewed
FROM
(
SELECT c.supplier_id, supplier_name, address1, address2, address3, address4, suppliertype, postcode, 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;
答案 2 :(得分:1)
如果您删除子选项,最终会得到以下内容:
SELECT c.supplier_id, supplier_name, address1, address2, address3, address4, suppliertype, postcode, contact_name,
COUNT(IF (q1.incomplete = '0', '0', null)) AS questions,
IF (active=1,'Yes', IF (active=2, 'NCR Only','Inactive')) AS rated,
COUNT(IF (q1.reviewed = '1', '1', null)) AS reviewed,
questapproved,
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仅计算相关行。
答案 3 :(得分:0)
我首先尝试通过供应商预先查询问题的数量并审核ONCE来进行重组。然后,加入其余的细节。通过使用STRAIGHT_JOIN关键字,它应按显示的顺序进行处理。这将首先预先聚合并使用THAT作为加入供应商和供应商站点的基础。无论如何都不需要外部组,因为它基于供应商ID。但是,对supplier_sites(您的ss.supplier_no)的加入意味着供应商有多个地点。这是否意味着地址和活动状态列来自该表?
问题的加入是否应与特定供应商相关联,是否与相应的网站位置相关?
此外,由于prequery在supplier_id!='0'上具有WHERE子句,因此它不需要下游,因为这将是与其他表正常连接的基础,从而将它们排除在结果集之外。< / p>
SELECT STRAIGHT_JOIN
PreAggregate.supplier_id,
PreAggregate.supplier_name,
address1,
address2,
address3,
address4,
suppliertype,
postcode,
contact_name,
PreAggregate.Questions,
IF (active=1,'Yes', IF (active=2, 'NCR Only','Inactive')) AS rated,
PreAggregate.Reviewed,
questapproved,
ss.supplier_no AS supplier_no
FROM
(select
s1.Supplier_ID,
s1.Supplier_Name,
SUM( IF( q1.Incomplete = '0', 1, 0 )) Questions,
SUM( IF( q1.Reviewed = '1', 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