【问题标题】:Most Efficient Filter Location of Subquery (GROUP BY) In JOINJOIN中子查询(GROUP BY)的最有效过滤位置
【发布时间】:2013-10-02 05:06:09
【问题描述】:
SELECT * FROM foo f
INNER JOIN (
    SELECT bar_id, MAX(revision_id) FROM bar b
    GROUP BY bar_id
) t ON t.bar_id = f.bar_id

好的,所以听到这个问题:假设这些表中有数百万条记录,我希望查询尽可能高效。

MySQL 是否会提取 bar 表的所有记录,然后在连接级别的 ON 语句而不是子查询内部过滤它们?或者有没有办法在 JOIN 过滤器之前只用 SQL 过滤子查询中的项目?

查询所有记录以过滤它们似乎效率低下,我还没有想到解决这个问题的方法。

我试过了,但是子查询看不到 foo 表:

SELECT * FROM foo f
INNER JOIN (
    SELECT bar_id, MAX(revision_id) FROM bar b
    WHERE b.bar_id = f.bar_id
    GROUP BY bar_id
) t ON t.bar_id = f.bar_id

有没有办法将 id 传递给子查询,我只是喜欢以最佳方式做事,我确信有办法做到这一点。

感谢所有回复。

【问题讨论】:

  • 可以添加索引来提高性能
  • 你也可以发布一个解释并显示创建表和记录数吗?

标签: mysql performance optimization join filter


【解决方案1】:

MySQL 是否会提取 bar 表的所有记录,然后在连接级别的 ON 语句而不是子查询内部过滤它们?

最有可能的是,它会在进行连接之前完整地执行子查询。如果您想确定,请查看EXPLAIN 显示的执行计划。

有一种特殊情况,这种方法甚至可能是有益的:如果bar 很大,但bar_id 只使用很少的值,并且如果foo 中的许多行引用了这些相同的少数bar_id 值,则选择在将它们加入foo 行之前,预先对每个 id 进行最大修订可能会很好。

或者有没有办法在 JOIN 过滤器之前仅使用 SQL 过滤子查询中的项目?

您可以完全避免子查询:

SELECT f.*, MAX(b.revison_id)
FROM foo f INNER JOIN bar b ON b.bar_id = f.bar_id
GROUP BY f.foo_id

我假设foo 中的每一行都可以由其foo_id 唯一标识;您可能必须在那里使用多个列,或引入新键。因此,对于foo 中的每一行,结果也将包含一行,但前提是bar 中也至少有一个匹配行。 bar 中的所有行都将在该 MAX 调用中聚合,因此您可以从中获得最大的 revision_id

我试过了,但是子查询看不到 foo 表:[…]

好在这不起作用。 工作的关闭是一些依赖查询,它必须重复执行,每个 foo 行一次。这是一个性能杀手。如果有疑问,请尝试使用您的真实数据并简单地比较足够多的执行次数的执行时间。

结论:尽量避免子查询,更努力避免依赖子查询。

【讨论】:

  • 你确定上面的代码会运行吗? SQL 标准规定,不属于聚合函数的每一列都应包含在 GROUP BY 子句中,而 foo 表中的列不...
  • MySQL 对规范的那部分没有那么严格,并允许通过选择任意列来进行未分组的列。但是你的问题提出了一个很好的观点:我隐含地假设 bar 中的每一行最多匹配 foo 中的一行,这可能是一个无效的假设。因此,您宁愿按一些唯一标识 foo 行的键进行分组。你有foo_id 吗?我会在我的回答中使用它。
猜你喜欢
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
  • 2014-02-20
  • 2016-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多