使用 CTE 在 Group by 之前或之后过滤

Posted

技术标签:

【中文标题】使用 CTE 在 Group by 之前或之后过滤【英文标题】:Filter before Group by or after with CTE 【发布时间】:2020-12-07 14:20:15 【问题描述】:

假设我有一个问题:

SELECT SUM(Data1), SUM(Data2), UserID 
FROM Table1
WHERE Data1 IN (1, 2, 3)
  AND USERID IN (SELECT USERID IN SOME SMALLISH Table of ~10000 Values)
GROUP BY UserID

此查询的性能如何?将其包装在 CTE 中并在分组后过滤掉 USERID 会更好吗?它会用 IN 扫描每一行吗?那么第一组应该快了吧?

编辑:添加了用户@jarlh 提到的缺失聚合

【问题讨论】:

这取决于数据库、表上的索引和分区,还可能取决于其他因素(取决于数据库)。 如果您必须使用默认解决方案,您会使用哪个?哪些因素会影响你朝一个或另一个方向发展? 不进行聚合时为什么要使用 GROUP BY?只需执行 SELECT DISTINCT! 对不起,这是我的错,实际上有一个聚合,它是我将编辑的 SUM。谢谢你告诉我。 相信优化器,写出易读的SQL! 【参考方案1】:

我倾向于将查询更改为使用EXISTS——尽管我不确定这是否会对 DB2 产生影响(某些数据库的优化器比其他数据库更好):

SELECT SUM(Data1), SUM(Data2), UserID 
FROM Table1 t1
WHERE Data1 IN (1, 2, 3) AND
      EXISTS (SELECT 1
              FROM smallish s
              WHERE t2.USERID = t1.USERID
             )
GROUP BY UserID;

那么,如果我理解正确,你的问题是这个查询是否会更好:

SELECT SUM(Data1), SUM(Data2), UserID 
FROM Table1 t1
WHERE Data1 IN (1, 2, 3)          
GROUP BY UserID
HAVING EXISTS (SELECT 1
              FROM smallish s
              WHERE t2.USERID = t1.USERID
             );

首先,您可以在数据和系统上测试这两个版本。这始终是验证性能问题的最佳方式。

其次,我希望WHERE 版本更快——而且更快——因为聚合要聚合的行要少得多。

一个例外是数据库可以使用索引进行聚合。我希望IN 能够排除这种可能性。另一个例外是如果EXISTS/IN 子句真的非常昂贵(比如说不涉及索引),那么每个结果行只运行一次可能会更快。也就是说,这与聚合中的大量数据相平衡。

【讨论】:

【参考方案2】:

我会推荐exists

select data1, data2, userid
from table1 t1
where 
    data1 in (1, 2, 3)
    and exists (select 1 from some_smallish_table s where s.userid = t.userid)
group by data1, data2, userid

然后,您要确保在some_smallish_table(userid) 上有一个索引,以便子查询快速执行。

【讨论】:

以上是关于使用 CTE 在 Group by 之前或之后过滤的主要内容,如果未能解决你的问题,请参考以下文章

Postgres - 使用 CTE 的 id 列的唯一值,与 GROUP BY 一起加入

Codeigniter 中由 distinct() 或 group_by() 过滤的计数结果

R语言使用dplyr包聚合(group_by)数据并过滤(fiter)之后再拆开聚合数据(ungroup取消组合)使用ggplot2可视化拆开分组后的线图(line plot)

在 R 中使用 dplyr 在 group_by 之后应用自定义函数

order by 和 group by 的区别?

SQL中group by 与 compute by