Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
优化PostgreSQL中的窗口函数以使用索引_Sql_Postgresql_Indexing_Greatest N Per Group_Window Functions - Fatal编程技术网

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

优化PostgreSQL中的窗口函数以使用索引,sql,postgresql,indexing,greatest-n-per-group,window-functions,Sql,Postgresql,Indexing,Greatest N Per Group,Window Functions,我在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的所有对中,日期是最大值。查询是众所周知的,通常使用

我在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\u NUMBER()的窗口函数

现在,我询问该查询的计划,发现
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)
正如预期的那样,排序占用了大部分查询执行时间,使用
index
es肯定会有帮助

因此,我在foo(id,date)
上创建了
create索引,希望现在可以使用索引。但事实并非如此。我用
外部合并
得到了相同的计划,甚至关闭
顺序扫描
也没有用。我刚刚完成了
位图索引扫描

->  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
是否可以使用索引进行排序?我想它不能但不明白为什么
groupaggreate
s可以提供良好的性能改进。

要匹配您创建的索引,请执行以下操作:

CREATE INDEX ON foo(id, date)
你必须做到:

ROW_NUMBER() OVER (PARTITION BY id ORDER BY date DESC NULLS LAST) 
但这可能不是你想问的。无论哪种方式,我都会制作索引:

CREATE INDEX ON foo(id, date DESC NULLS LAST)
因此,
max(date)
是每个
id
的第一个索引项。 相关的:

您可以将逻辑“日期是具有相同id的所有对中的最大日期”改写为直接翻译:

SELECT id, date
FROM (
    SELECT id, date, MAX(date) OVER (PARTITION BY id) as maxDate
    FROM foo
) sbt
WHERE date = maxDate;

它与
行号
不完全相同,而是
,它可能返回多个具有相同
日期的行

您的排序在磁盘上进行。尝试增加会话的
work\u mem
,看看这是否有所改善things@a_horse_with_no_name是的,我知道改进
work\u mem
会将排序算法切换到
快速排序
,如果内存足够的话。但是为什么我们不能将
foo(id,date)
上的索引提供的排序与窗口函数一起使用呢?用聚合的我们可以。不幸的是,这对我不起作用。你确定还是我做错了什么…?我的意思是
(按id顺序分区,按ASC上次为空的日期)
Awesom,你只是个向导!!!我将索引重新创建为
createindex ON foo(id,date DESC NULLS LAST)
,它工作得非常好(性能提高了两倍)。但是,你不能添加一些解释或参考资料来阅读更多关于为什么像我这样创建索引不适用于窗口聚合的内容。@St.Antario:我添加了一些相关的答案,其中包含了更多的细节和链接。
CREATE INDEX ON foo(id, date DESC NULLS LAST)
SELECT id, date
FROM (
    SELECT id, date, MAX(date) OVER (PARTITION BY id) as maxDate
    FROM foo
) sbt
WHERE date = maxDate;