[英]Improving performance of LEFT JOIN / GROUP BY
我有两个表snippets
和platforms
。 每个片段都属于一个平台(fork_id可为空,并且链接到同一表上的另一条记录)。 结构体:
PLATFORMS (id, name, slug, syntax)
SNIPPETS (id, platform_id, fork_id, private etc.)
我现在正在尝试运行查询以获取每个平台的片段总数。 当摘要表具有一百万条记录时,查询速度很慢(在10到20秒之间)。
SELECT platforms.id, name, slug, syntax, COUNT(*) AS total FROM platforms
LEFT JOIN snippets on platforms.id = snippets.platform_id
WHERE fork_id IS NULL
AND private = 0
GROUP BY platforms.id, name
ORDER BY total DESC, name asc;
一些其他信息:
运行EXPLAIN
查询可提供以下内容:
如何使性能达到可接受的水平? 谢谢!
在MySQL中,使用相关子查询可以更快地进行这种查询:
SELECT p.id, p.name, p.slug, p.syntax,
(SELECT COUNT(*)
FROM snippets s
WHERE p.id = s.platform_id AND
s.fork_id IS NULL AND
s.private = 0
) AS total
FROM platforms p
ORDER BY total DESC, name asc;
然后,您想要在snippets(platform_id, fork_id, private)
上建立索引。
请注意,您的原始查询等同于:
SELECT p.id, p.name, p.slug, p.syntax, COUNT(*) AS total
FROM platforms p JOIN
snippets s
on p.id = s.platform_id
WHERE s.fork_id IS NULL AND s.private = 0
GROUP BY p.id, p.name
ORDER BY total DESC, name asc;
因为WHERE
子句将LEFT JOIN
转换为INNER JOIN
。 对于此查询,您可以尝试在snippets(private, fork_id, platform_id)
上建立索引。
我可以看到两件事。 一个是计数,另一个是显示platforms
表中的详细信息。
让我们先数一下。
SELECT platform_id, COUNT(*) snips
FROM snippets
WHERE fork_id IS NULL
AND private = 0
GROUP BY platform_id
为了使此过程尽可能快,请在snippets
表的( private, fork_id, platform_id)
列上创建一个复合索引。 这样,内部查询就可以进行所谓的索引扫描,您可以对其进行读取。
现在,有了数量,让我们报告详细信息。
SELECT a.id, a.name, a.slug, a.syntax, b.snips
FROM platforms a
LEFT JOIN (
SELECT platform_id, COUNT(*) snips
FROM snippets
WHERE fork_id IS NULL
AND private = 0
GROUP BY platform_id
) b ON a.platform_id = b.platform_id
ORDER BY b.snips DESC, a.name ASC;
诀窍是:简化简化(聚合)大型表时的简化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.