快速选择另一个表中具有“1 个或多个”匹配行的所有行
Posted
技术标签:
【中文标题】快速选择另一个表中具有“1 个或多个”匹配行的所有行【英文标题】:Quickly select all rows with "1 or more" matching rows in another table 【发布时间】:2009-05-26 02:11:32 【问题描述】:我想以最有效的方式从一个表中选择与另一个表中的“一个或多个”行匹配的所有行。
SELECT identity.id FROM identity
INNER JOIN task ON
task.identityid=identity.id
AND task.groupid IN (78, 122, 345, 12, 234, 778, 233, 123, 33)
目前,如果有多个匹配任务,这会多次返回相同的身份(但稍后消除这些的性能损失并不算太糟糕)。我希望它只为每个身份返回一行,它与这些任务组中的一个或多个匹配,我想知道是否有比 DISTINCT 或 GROUP BY 更有效的方法。
使用 DISTINCT 或 GROUP BY 的问题在于,仍然会扫描任务表以查找所有 groupid 匹配项,然后通过临时表(有时使用文件排序)将它们减少为一个。我宁愿它进行某种短路评估 - 在找到相同身份后,不要进一步追求任何后续任务匹配。
我正在考虑执行 EXISTS 子查询,但我不知道如何优化这些子查询。我需要它在身份表之前先加入任务表,所以我没有对身份表进行全面扫描,因为身份表非常大并且会有很多不匹配。
【问题讨论】:
您可以通过在 (groupid, identityid) 上提供索引来优化任务表扫描——考虑到我在 WHERE EXISTS 或 mysql 中其他子查询方面的性能经验,这似乎是一种更有前途的方法(如果子查询的优化在 6.0 中发生了革命性的变化,请告诉我,我会打破泡沫!-) 是的,我的任务表上的 PRIMARY 已经是这样了(每个身份每个任务组一个任务),所以它非常有效。 【参考方案1】:只使用“SELECT DISTINCT”和你所拥有的东西在mysql中应该是有效的。您可能需要将值放入表中并加入其中,而不是使用“IN (...)”。
【讨论】:
当我使用“DISTINCT”时,它显示“使用临时表”。对于我的简化测试来说,它似乎仍然相当快,但这不会增加相当多的开销,可以赶上我吗? DISTINCT 的临时表是否曾经快速/在内存中? 注意变化。 Mysql 确实喜欢做临时表,但通常相当有效。 WHERE EXISTS 策略通常是最常见的跨服务器推荐,也应该有效。 (WHERE ... IN ( ... ) 让我不寒而栗 - 它通常意味着自动 UNION。)【参考方案2】:MYSQL 是否支持 TOP N 语法?如果是这样:
SELECT TOP 1 identity.id FROM identity
INNER JOIN task ON
task.identityid=identity.id
AND task.groupid IN (78, 122, 345, 12, 234, 778, 233, 123, 33)
【讨论】:
mysql 语法(而不是 SELECT 之后的 TOP 1)将在查询末尾添加 ORDER BY identity.id DESC LIMIT 1 - 但 TOP 或 LIMIT 产生单行答案这似乎与问题要求的完全不同。【参考方案3】:只要您在子查询中比较的列已编入索引,Exists 就应该对您执行得很好。
我希望 exists 的性能会比 join-and-group-by 好一点,但我必须尝试一下才能确定。我在 MySQL 中遇到了足够多的性能问题,我的预测是错误的,我知道值得一试。
【讨论】:
我试了一下,EXPLAIN显示它在任务表之前加入了身份表,所以它对身份表中的每一行都执行了子查询。这不是我想要的顺序,但很难说这是否仅仅是因为我拥有的测试数据太小了——也许它会以更多的身份加入它。我必须用大量数据进行测试才能找出答案! 我想我也可能误解了 EXPLAIN 如何显示子查询的连接顺序...以上是关于快速选择另一个表中具有“1 个或多个”匹配行的所有行的主要内容,如果未能解决你的问题,请参考以下文章
MYSQL 从具有 100 万行的表中选择 distinct(indexed_column)
如何从1个表中选择许多行并将其插入另一个表中特定行的特定JSONB字段中?但是在单个原始SQL查询中