我是stackoverflow中的新手。 我的查询花了很多时间(超过5分钟)。 这个查询可以变得更快吗? 请!帮我!我不知道:(
我有2个表插座和销售: 1.出口:具有唯一数据的表格 - id_outlet - name_outlet 2.销售:像插座的细节(1个插座有很多数据) - id_outlet - msisdn(1个出口超过1 msisdn) - 日期
所以,我需要获取数据: 1.分支 2.插座数量 3.活动插座数量(我从本月检查现有插座获得此数据) 3.计数msisdn 4.后退检查插座的数量(我从上个月检查现有插座获得此数据,但本月不存在) 5.新活动插座的数量(我从本月检查现有插座获得此数据,但在上个月不存在) 6.非活动插座的数量(我从上个月和本月检查该插座不存在获得此数据) 7. Consistant Outlet的数量(我从本月和上个月检查现有商店获得此数据)
SELECT branch br, COUNT(DISTINCT id_outlet) AS tot_outlet,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS aktif,
(SELECT COUNT(msisdn) FROM sales s, outlet o
WHERE ".$outlet['status'][$i]." and s.date LIKE '".$thisMonth."%' AND o.active=1 AND s.id_outlet = o.id_outlet
AND s.branch=br) AS supply,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS back_checking,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS new_aktif,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS non_aktif,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS konsisten
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1
GROUP BY branch
答案 0 :(得分:0)
自己诊断的几个步骤。
解释您的疑问。
要解释您的查询,这很简单;您只需要在EXPLAIN
部分的前面添加SELECT
。
运行此;
EXPLAIN SELECT branch br, COUNT(DISTINCT id_outlet) AS tot_outlet,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS aktif,
(SELECT SUM(featurephone) FROM outlet o
WHERE ".$outlet['status'][$i]."
AND active=1 AND branch = br) AS feature,
(SELECT SUM(smartphone) FROM outlet o
WHERE ".$outlet['status'][$i]."
AND active=1 AND branch = br) AS smart,
(SELECT COUNT(msisdn) FROM sales s, outlet o
WHERE ".$outlet['status'][$i]." and s.date LIKE '".$thisMonth."%' AND o.active=1 AND s.id_outlet = o.id_outlet
AND s.branch=br) AS supply,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS back_checking,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS new_aktif,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet NOT IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS non_aktif,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1 AND branch = br
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$lastMonth."%')
AND id_outlet IN (SELECT DISTINCT id_outlet FROM sales WHERE DATE LIKE '".$thisMonth."%')) AS konsisten
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1
GROUP BY branch
这将提供类似于此的输出:
简要说明您应该寻找什么。最重要的是type
,possible_keys
和key
。主要是type
。
Type的值可以告诉您它是如何查找查询的。列表(按从最好到最差的顺序)是:system, const, eq_ref, ref, fulltext, ref_or_null, unique_subquery, index_subquery, range, index, all
。你不想要任何全部;而且最有可能的是,主要关注ref和eq_ref。由于查询的结构,您可能会有子查询。
要解决这个问题,我要做的是查看表的结构和查询。任何将从排序列表(基本上是索引)中受益的东西都会被索引。对我来说,这意味着我将索引任何外键ID(即使你不使用外键,设置索引);任何属性,如删除,可见或其他。
简单地说,我将大多数在查询的where
部分中进行比较的内容编入索引。这是一个好的开始;从那里,你真的应该优化的东西,因为索引可以使用大量的内存,但这是性能提升的良好开端。
答案 1 :(得分:0)
避免在子查询中使用子查询,那么你应该能够做到这样的事情: -
SELECT branch br, COUNT(DISTINCT id_outlet) AS tot_outlet,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
INNER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]."
AND o.active=1
AND o.branch = br) AS aktif,
(SELECT COUNT(msisdn) FROM sales s, outlet o
WHERE ".$outlet['status'][$i]."
and s.date LIKE '".$thisMonth."%'
AND o.active=1
AND s.id_outlet = o.id_outlet
AND s.branch=br) AS supply,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
INNER JOIN sales s1 ON o.id_outlet = s1.id_outlet AND s1.DATE LIKE '".$lastMonth."%'
LEFT OUTER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]."
AND o.active=1
AND o.branch = br
AND s2.id_outlet IS NULL) AS back_checking,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
LEFT OUTER JOIN sales s1 ON o.id_outlet = s1.id_outlet AND s1.DATE LIKE '".$lastMonth."%'
INNER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]."
AND o.active=1
AND o.branch = br
AND s1.id_outlet IS NULL) AS new_aktif,
(SELECT COUNT(DISTINCT(o.id_outlet))
FROM outlet o
LEFT OUTER JOIN sales s1 ON o.id_outlet = s1.id_outlet AND s1.DATE LIKE '".$lastMonth."%'
LEFT OUTER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]."
AND o.active=1
AND o.branch = br
AND s1.id_outlet IS NULL
AND s2.id_outlet IS NULL) AS non_aktif,
(SELECT COUNT(DISTINCT(o.id_outlet))
FROM outlet o
INNER JOIN sales s1 ON o.id_outlet = s1.id_outlet AND s1.DATE LIKE '".$lastMonth."%'
INNER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]." AND o.active=1 AND o.branch = br) AS konsisten
FROM outlet o
WHERE ".$outlet['status'][$i]." AND active=1
GROUP BY branch
这仍然在SELECT中使用多个子查询,但是根据WHERE子句(即$ outlet ['status'] [$ i]的值),这可能不会太糟糕。
我知道你说你已经做到了这一点,但它给出了错误的结果,但是如果没有示例数据和表格布局,我无法做任何检查以确定这应该是错误的原因或原因。
有可能将连接放在主查询中,至少替换最后4个子查询: -
SELECT branch br, COUNT(DISTINCT id_outlet) AS tot_outlet,
(SELECT COUNT(DISTINCT(id_outlet))
FROM outlet o
INNER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]."
AND o.active=1
AND o.branch = br) AS aktif,
(SELECT COUNT(msisdn) FROM sales s, outlet o
WHERE ".$outlet['status'][$i]."
and s.date LIKE '".$thisMonth."%'
AND o.active=1
AND s.id_outlet = o.id_outlet
AND s.branch=br) AS supply,
COUNT(DISTINCT IF(s1.id_outlet IS NOT NULL AND s2.id_outlet IS NULL, o.id_outlet, NULL) AS back_checking
COUNT(DISTINCT IF(s1.id_outlet IS NULL AND s2.id_outlet IS NOT NULL, o.id_outlet, NULL) AS new_aktif
COUNT(DISTINCT IF(s1.id_outlet IS NULL AND s2.id_outlet IS NULL, o.id_outlet, NULL) AS non_aktif
COUNT(DISTINCT IF(s1.id_outlet IS NOT NULL AND s2.id_outlet IS NOT NULL, o.id_outlet, NULL) AS konsisten
FROM outlet o
LEFT OUTER JOIN sales s1 ON o.id_outlet = s1.id_outlet AND s1.DATE LIKE '".$lastMonth."%'
LEFT OUTER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '".$thisMonth."%'
WHERE ".$outlet['status'][$i]." AND active=1
GROUP BY branch
这依赖于仅计算非空值的COUNT(某个表达式)。
EDIT。
一个选项是将核心子查询更改为非核心子查询,您可以对其进行连接。然后,每次只执行一次,而不是每次返回一次。缺点是加入子查询结果不会使用索引,因此连接可能不会那么快。哪个更有效取决于数据量。
使用我之前的查询并更改atkif和supply字段以使用非核心子查询,可以得到: -
SELECT o.branch br,
COUNT(DISTINCT o.id_outlet) AS tot_outlet,
COALESCE(sub_aktif.aktif, 0) AS aktif,
COALESCE(sub_supply.supply, 0) AS supply,
COUNT(DISTINCT IF(s1.id_outlet IS NOT NULL AND s2.id_outlet IS NULL, o.id_outlet, NULL)) AS back_checking,
COUNT(DISTINCT IF(s1.id_outlet IS NULL AND s2.id_outlet IS NOT NULL, o.id_outlet, NULL)) AS new_aktif,
COUNT(DISTINCT IF(s1.id_outlet IS NULL AND s2.id_outlet IS NULL, o.id_outlet, NULL)) AS non_aktif,
COUNT(DISTINCT IF(s1.id_outlet IS NOT NULL AND s2.id_outlet IS NOT NULL, o.id_outlet, NULL)) AS konsisten
FROM outlet o
LEFT OUTER JOIN
(
SELECT o.branch, COUNT(DISTINCT(o.id_outlet)) AS aktif
FROM outlet o
INNER JOIN sales s
ON o.id_outlet = s.id_outlet
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%')
AND s.DATE LIKE '2014-10%' AND o.active=1
GROUP BY o.branch
) sub_aktif
ON sub_aktif.branch = o.branch
LEFT OUTER JOIN
(
SELECT s.branch, COUNT(msisdn) AS supply
FROM sales s
INNER JOIN outlet o
ON s.id_outlet = o.id_outlet
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%')
AND s.date LIKE '2014-10%' AND o.active=1
GROUP BY s.branch
) sub_supply
ON sub_supply.branch = o.branch
LEFT OUTER JOIN sales s1 ON o.id_outlet = s1.id_outlet AND s1.DATE LIKE '2014-09%'
LEFT OUTER JOIN sales s2 ON o.id_outlet = s2.id_outlet AND s2.DATE LIKE '2014-10%'
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%')
AND active=1
GROUP BY o.branch ;
更改原始查询以对所有字段执行此操作会产生以下结果: -
SELECT o.branch br, COUNT(DISTINCT id_outlet) AS tot_outlet,
COALESCE(sub_aktif.aktif, 0) AS aktif,
COALESCE(sub_supply.supply, 0) AS supply,
COALESCE(sub_back_checking.back_checking, 0) AS back_checking,
COALESCE(sub_new_aktif.new_aktif, 0) AS new_aktif,
COALESCE(sub_non_aktif.non_aktif, 0) AS non_aktif,
COALESCE(sub_konsisten.konsisten, 0) AS konsisten
FROM outlet o
LEFT OUTER JOIN
(
SELECT o.branch, COUNT(DISTINCT(o.id_outlet)) AS aktif
FROM outlet o
INNER JOIN sales s
ON o.id_outlet = s.id_outlet
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%')
AND s.DATE LIKE '2014-10%' AND o.active=1
GROUP BY o.branch
) sub_aktif
ON sub_aktif.branch = o.branch
LEFT OUTER JOIN
(
SELECT s.branch, COUNT(msisdn) AS supply
FROM sales s
INNER JOIN outlet o
ON s.id_outlet = o.id_outlet
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%')
AND s.date LIKE '2014-10%' AND o.active=1
GROUP BY s.branch
) sub_supply
ON sub_supply.branch = o.branch
LEFT OUTER JOIN
(
SELECT o.branch, COUNT(DISTINCT(o.id_outlet)) AS back_checking
FROM outlet o
INNER JOIN sales s1
ON s1.id_outlet = o.id_outlet AND s1.DATE LIKE '2014-09%'
LEFT OUTER JOIN sales s2
ON s2.id_outlet = o.id_outlet AND s2.DATE LIKE '2014-10%'
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%') AND active=1
AND s2.id_outlet IS NULL
GROUP BY o.branch
) sub_back_checking
ON sub_back_checking.branch = o.branch
LEFT OUTER JOIN
(
SELECT o.branch, COUNT(DISTINCT(o.id_outlet)) AS new_aktif
FROM outlet o
LEFT OUTER JOIN sales s1
ON s1.id_outlet = o.id_outlet AND s1.DATE LIKE '2014-09%'
INNER JOIN sales s2
ON s2.id_outlet = o.id_outlet AND s2.DATE LIKE '2014-10%'
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%') AND active=1
AND s1.id_outlet IS NULL
GROUP BY o.branch
) sub_new_aktif
ON sub_new_aktif.branch = o.branch
LEFT OUTER JOIN
(
SELECT o.branch, COUNT(DISTINCT(o.id_outlet)) AS non_aktif
FROM outlet o
LEFT OUTER JOIN sales s1
ON s1.id_outlet = o.id_outlet AND s1.DATE LIKE '2014-09%'
LEFT OUTER JOIN sales s2
ON s2.id_outlet = o.id_outlet AND s2.DATE LIKE '2014-10%'
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%') AND active=1
AND s1.id_outlet IS NULL
AND s2.id_outlet IS NULL
GROUP BY o.branch
) sub_non_aktif
ON sub_non_aktif.branch = o.branch
LEFT OUTER JOIN
(
SELECT o.branch, COUNT(DISTINCT(o.id_outlet)) AS konsisten
FROM outlet o
INNER JOIN sales s1
ON s1.id_outlet = o.id_outlet AND s1.DATE LIKE '2014-09%'
INNER JOIN sales s2
ON s2.id_outlet = o.id_outlet AND s2.DATE LIKE '2014-10%'
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%') AND active=1
GROUP BY o.branch
) sub_konsisten
ON sub_konsisten.branch = o.branch
WHERE (o.STATUS LIKE 'MALL%' OR o.STATUS LIKE 'STREET%' OR o.STATUS LIKE 'TOP TEN%' OR o.STATUS LIKE 'LIFESTYLE%') AND active=1
GROUP BY o.branch;
sql小提琴在这里: -