中小型表上的左连接非常慢
Posted
技术标签:
【中文标题】中小型表上的左连接非常慢【英文标题】:Very slow Left Join on small/medium tables 【发布时间】:2015-07-31 15:08:57 【问题描述】:我遇到了一个问题,即某个特定的左连接大大减慢了重要查询的速度。使用 phpMyAdmin 测试查询,它指出查询需要 3.9 秒才能返回 546 行,但我不得不等待 67 秒才能看到结果,这让我觉得很奇怪。
涉及两个表: nsi(1,553 行)和文件(233,561 行)。此查询中提到的所有列都被单独索引,并且文件表中的 filejobid、category 和 isactive 上有一个复合索引。被比较的所有东西也是一个整数。
这个查询的淡化版本的目标是显示 nsi 表中的行一次,并能够确定是否有人上传了类别 20 的文件。可以有多个文件,但应该只有一行,因此是分组。
查询:
SELECT
nsi.id AS id,
f.id AS filein
FROM nsi nsi
LEFT JOIN files f
ON f.filejobid=nsi.leadid AND f.category=20 AND f.isactive=1
WHERE nsi.isactive=1
GROUP BY nsi.id
此数据的 67 秒加载时间对于我的应用程序来说简直是不可接受的,我不知道如何进一步优化它。我已经索引和复合索引。我是否应该只考虑一个新的更迂回的解决方案?
感谢您的帮助!
【问题讨论】:
你只需要一个索引,如果它不好,查询优化器会选择一个更好的。您应该删除每列上不必要的开销的单个索引。加上删除该复合索引。当我确定它是 1 或 0 时使用 isactive ,因此两种可能的情况会抓取您的整个数据集而不是分区。基于这个淡化的查询,我会将您的索引仅放在 nsi.id 上。 我不知道你认为你想做什么。如果您愿意,请考虑遵循这个简单的两步操作: 1. 如果您还没有这样做,请提供适当的 DDL(和/或 sqlfiddle),以便我们可以更轻松地复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。 FirebladeDan 实际上完全按照我的需要解决了它。删除化合物和 isactive 索引大大加快了它的速度。我没有考虑过会以这种方式使用更多索引来为 SQL 创建更多工作。有趣的东西。谢谢你,FirebladeDan! 是的没问题的首席 【参考方案1】:这是您的查询,我觉得这有点可疑,因为您在 f.id
上有聚合但没有聚合功能。它将返回一个任意匹配的 id:
SELECT nsi.id AS id, f.id AS filein
FROM nsi LEFT JOIN
files f
ON f.filejobid = nsi.leadid AND f.category = 20 AND f.isactive = 1
WHERE nsi.isactive = 1
GROUP BY nsi.id;
对于这个查询,我认为最好的索引是files(filejobid), category, isactive)
和nsi(isactive, filejobid, id)
。
但是您可以轻松地重写查询以提高效率,因为它不需要 group by
(假设 nsi.id
是唯一的):
SELECT nsi.id AS id,
(SELECT f.id
FROM files f
WHERE f.filejobid = nsi.leadid AND f.category = 20 AND f.isactive = 1
LIMIT 1
) AS filein
FROM nsi
WHERE nsi.isactive = 1;
同样的索引也适用于此。
如果您想要一个匹配文件的列表,而不仅仅是一个,请在任一查询中使用 group_concat()
。
【讨论】:
以上是关于中小型表上的左连接非常慢的主要内容,如果未能解决你的问题,请参考以下文章
MYSQL:与 Group_Concatenate 一起使用的两个表上的左连接