我目前有一个查询,从两个表中选择指标数据,同时让项目从另外两个表中查询(一个是拥有项目,另一个是用户可以访问的项目)。
SELECT v.`projectID`,
(SELECT COUNT(m.`session`)
FROM `metricData` m
WHERE m.`projectID` = v.`projectID`) AS `sessions`,
(SELECT COUNT(pb.`interact`)
FROM `interactionData` pb WHERE pb.`projectID` = v.`projectID` GROUP BY pb.`projectID`) AS `interactions`
FROM `medias` v
LEFT JOIN `projectsExt` pa ON v.`projectsExtID` = pa.`projectsExtID`
WHERE (pa.`user` = '1' OR v.`ownerUser` = '1')
GROUP BY v.`projectID`
这需要太长时间,1-2秒。这显然是多左连接方案。但是,我有一些提高速度的想法,并且想知道原则上的想法是什么。我: -
答案 0 :(得分:4)
这里有两个问题:
要正确回答#1,必须提供更多信息。技术信息,例如此特定查询的解释计划是一个良好的开端。如果我们拥有您访问的所有表的SHOW CREATE TABLE以及它们包含的行数,那就更好了。
但我也很欣赏更多功能性信息:您要回答的问题究竟是什么?现在,看起来你正在看两组不同的媒体:
由于缺乏足够的信息来回答#1,我可以回答#2 - “如何避免左连接”。答案是:写一组两个UNION,一个有匹配,一个没有匹配。
SELECT v.`projectID`
, (
SELECT COUNT(m.`session`)
FROM `metricData` m
WHERE m.`projectID` = v.`projectID`
) AS `sessions`
, (
SELECT COUNT(pb.`interact`)
FROM `interactionData` pb
WHERE pb.`projectID` = v.`projectID`
GROUP BY pb.`projectID`
) AS `interactions`
FROM (
SELECT v.projectID
FROM medias
WHERE ownerUser = '1'
GROUP BY projectID
UNION ALL
SELECT v.projectID
FROM medias v
INNER JOIN projectsExt pa
ON v.projectsExtID = pa.projectsExtID
WHERE v.ownerUser != '1'
AND pa.user = '1'
GROUP BY v.`projectID
) v
答案 1 :(得分:0)
您是否尝试过将所有内容重构为左连接?看到你如何总是在同一领域进行分组,这不应该是一个问题。试试并发布EXPLAIN
以查看瓶颈是什么。
子选择的性能低于连接,因为引擎可以将连接优化到更高的程度。实际上,在适用的情况下,子选择通常会在可能的情况下被引擎重写为连接。
作为一个经验法则,分割查询没有任何好处,你获得的只是开销和混淆优化器。这个规则一如既往地存在例外情况,但是在您完成传统工作并且知道自己热衷于这种方法之后,它们就会发挥作用。