【问题标题】:Optimize a max() aggregate that works for "no rows", too优化适用于“无行”的 max() 聚合
【发布时间】:2012-12-27 16:40:21
【问题描述】:

我有一个查询,我正在尝试针对 PostgreSQL 9.2 进行优化:

select coalesce(max(id),0) as m from tbl

它需要永远运行,所以我想我可以将它重写为

select id from tbl order by id desc limit 1

如果表中没有行,则需要返回0。我尝试了一些案例陈述的组合,但它们似乎不起作用。有什么建议吗?

准备一张空桌子:

Aggregate (cost=11.25..11.26 rows=1 width=4)
 -> Seq Scan on tbl (cost=0.00..11.00 rows=100 width=4)

成本是 58k,表有 1,190,000 行,但执行计划相同。

【问题讨论】:

  • a m 是什么?错字?应该是select coalesce(max(id),0) AS m from tbl
  • @a_horse_with_no_name id 是主键 这是一个空表的计划 "Aggregate (cost=11.25..11.26 rows=1 width=4)" " -> Seq Scan on tbl (cost= 0.00..11.00 rows=100 width=4)" 成本为 58k,表有 1,190,000 行,但执行计划相同
  • 这是我希望计划的样子:explain.depesz.com/s/hp8(表有 5000000 行)
  • 自动真空已开启。经过分析,行估计为 1,成本为 59k。运行 set enable_seqscan=off 仍然会进行 seq 扫描
  • 一定有你没有告诉我们的事情。很难相信 PostgreSQL 9.2 在 PK 上执行 max() 时实际上会执行全表扫描(请参阅我的 explain.depesz.com 链接)。

标签: postgresql aggregate-functions postgresql-9.2 postgresql-performance


【解决方案1】:

如果表中没有行则需要返回0

SELECT COALESCE((SELECT max(id) FROM tbl), 0)

由于没有返回行,您不能简单地使用COALESCE() 为这种特殊类型的NULL(无行)提供默认值。将其放入子查询中。
要点:如果tbl 的所有现有行都具有id IS NULL,这也会返回0

性能的关键是tbl.id 上的索引 可能是主(或唯一)键约束,它通过列上的唯一索引或任何普通 b- 来实现树索引:

CREATE index foo on tbl(id)

密切相关的问题:
How to display a default value when no match found in a query?

【讨论】:

    【解决方案2】:

    也许是这样的:

    select
        case
            when (select id from tbl limit 1) is null then 0
            else (select id from tbl order by id desc limit 1)
        end;
    

    【讨论】:

    • select count(1) from tbl 将导致对表进行全扫描,从而导致查询非常慢。
    猜你喜欢
    • 2016-11-05
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 2021-12-17
    相关资源
    最近更新 更多