微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

优化PostgreSQL中的窗口函数以使用索引

我在Postgresql 9.2 DB中有一个表,创建并填充如下:

CREATE TABLE foo( id integer,date date );

INSERT INTO foo
SELECT (id % 10) + 1,Now() - (id % 50) * interval '1 day'
FROM generate_series(1,100000) AS id;

现在,我需要找到所有对(id,date),使得日期是具有相同id的所有对中的最大值.该查询是众所周知的,并且通常使用名为ROW_NUMBER()的窗口函数

SELECT id,date
FROM (
    SELECT id,date,ROW_NUMBER() OVER (PARTITION BY id ORDER BY date DESC) rn
    FROM foo
) sbt
WHERE sbt.rn = 1;

现在,我询问该查询的计划,并发现WindowAgg节点需要先对表进行排序.

Subquery Scan on sbt  (cost=11116.32..14366.32 rows=500 width=8) (actual time=71.650..127.809 rows=10 loops=1)
  Filter: (sbt.rn = 1)
  Rows Removed by Filter: 99990
    ->  WindowAgg  (cost=11116.32..13116.32 rows=100000 width=8) (actual time=71.644..122.476 rows=100000 loops=1)
          ->  Sort  (cost=11116.32..11366.32 rows=100000 width=8) (actual time=71.637..92.081 rows=100000 loops=1)
                Sort Key: foo.id,foo.date
                Sort Method: external merge  disk: 1752kB
                ->  Seq Scan on foo  (cost=0.00..1443.00 rows=100000 width=8) (actual time=0.006..6.138 rows=100000 loops=1)

正如预期的那样,排序占用了大部分查询执行时间,使用索引肯定会有所帮助.

所以我创建了CREATE INDEX ON foo(id,date)并期望现在它将使用索引.但事实并非如此.我与外部合并有相同的计划,甚至关闭顺序扫描也没用.我刚刚结束了位图索引扫描

->  Sort  (cost=12745.58..12995.58 rows=100000 width=8) (actual time=69.247..90.003 rows=100000 loops=1)
      Sort Key: foo.id,foo.date
      Sort Method: external merge  disk: 1752kB
      ->  Bitmap Heap Scan on foo  (cost=1629.26..3072.26 rows=100000 width=8) (actual time=5.359..12.639 rows=100000 loops=1)
            ->  Bitmap Index Scan on foo_id_date_idx  (cost=0.00..1604.26 rows=100000 width=0) (actual time=5.299..5.299 rows=100000 loops=1)


WindowAgg可以使用索引进行排序吗?我认为它不得不理解为什么…… GroupAggreagtes可以和它提供良好的性能提升.

解决方法

要匹配您创建的索引:

CREATE INDEX ON foo(id,date)

你必须这样做:

ROW_NUMBER() OVER (PARTITION BY id ORDER BY date DESC NULLS LAST)

这是ASC完美的逆序.

除此之外,您可以运行:

SELECT disTINCT ON (id)
       id,date
FROM   foo
ORDER  BY id,date DESC NULLS LAST;

但那可能不是你想问的问题.无论哪种方式,我都会制作索引:

CREATE INDEX ON foo(id,date DESC NULLS LAST)

这样max(date)是每个id的第一个索引条目.
有关:

> PostgreSQL sort by datetime asc,null first?
> Why do NULL values come first when ordering DESC in a PostgreSQL query?
> Select first row in each GROUP BY group?
> Optimize groupwise maximum query

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐