避免冗余聚合函数和/或按列分组的最佳方法

jph*_*jph 7 postgresql performance subquery postgresql-9.3 query-performance

假设我有两个表:

福:

id
baz
Run Code Online (Sandbox Code Playgroud)

酒吧:

id
foo_id
boom
Run Code Online (Sandbox Code Playgroud)

所以一个 Foo 有很多 Bars。我经常发现自己需要为给定的一组 Foo 计算跨条的聚合,但我也想要一些来自 Foo 的属性。这样做的两种最直接的方法是丑陋的:

方法#1:不必要的聚合函数

select
  foo.id,
  min(foo.baz) as baz,
  min(bar.boom) as min_boom
from
  foo
join
  bar on foo.id = bar.foo_id
group by
  foo.id;
Run Code Online (Sandbox Code Playgroud)

方法#2:不必要的按列分组

select
  foo.id,
  foo.baz,
  min(bar.boom) as min_boom
from
  foo
join
  bar on foo.id = bar.foo_id
group by
  foo.id,
  foo.baz;
Run Code Online (Sandbox Code Playgroud)

当 Foo 除了“id”之外只有一个额外的列时,这并不是那么糟糕,但是如果需要包含许多列,那么分组的效率就会大大降低。像这样的查询解决了这两个问题,但似乎很笨拙:

select
  foo.id,
  foo.baz,
  x.min_boom
from
  foo
join
  (select
    foo_id, 
    min(boom) as min_boom
  from
    bar
  group by
    foo_id) x on x.foo_id = foo.id;
Run Code Online (Sandbox Code Playgroud)

有没有更好的办法?如果重要的话,平台是 Postgres。

And*_*y M 11

如果ID被定义作为主键,你可以省略所有分组,你只要想为输出作为你被分组列ID。这种分组的特殊情况符合当前的 SQL 标准,并且在PostgreSQL 手册 中也有介绍,从 9.1 版本开始:

当存在 GROUP BY 或存在任何聚合函数时,SELECT 列表表达式引用未分组的列是无效的,除非在聚合函数内或当未分组的列在功能上依赖于分组的列时,否则会有更多为未分组的列返回一个可能的值。如果分组列(或其子集)是包含未分组列的表的主键,则存在函数依赖性。

(加了重点。)

因此,如果foo.id是 PK,则此查询将有效:

select
  foo.id,
  foo.baz,
  foo.whatever,
  min(bar.boom) as min_boom
from
  foo
join
  bar on foo.id = bar.foo_id
group by
  foo.id;
Run Code Online (Sandbox Code Playgroud)

  • 是的!限制是它必须是`PRIMARY KEY`,它尚未(尚未)为`UNIQUE` 约束实现。 (5认同)