postgresql 分块查询中的全局行号

v8wbuo2f  于 2023-01-25  发布在  PostgreSQL
关注(0)|答案(4)|浏览(192)

我想在结果集中包含一个列row_number,列号为行号序列,其中1是最新的项,没有间隔。

SELECT id, row_number() over (ORDER BY id desc) AS row_number, title
FROM mytable
WHERE group_id = 10;

现在,我希望以1000个数据块为单位查询相同的数据,以便节省内存:

SELECT id, row_number() over (ORDER BY id desc) AS row_number, title
FROM mytable
WHERE group_id = 10 AND id >= 0 AND id < 1000
ORDER BY id ASC;

这里,对于每个块,row_number都从1开始,但是我希望它像第一种情况一样,好像是全局查询的一部分。

njthzxwz

njthzxwz1#

假设:

  • id定义为PRIMARY KEY-这意味着UNIQUENOT NULL。否则,您可能必须处理NULL值和/或重复值(并列)。
  • 您没有对表的并发写访问权限-或者您不关心拍摄快照后发生了什么。

MATERIALIZED VIEW,就像您演示的in your answer一样,是一个很好的选择。

CREATE MATERIALIZED VIEW mv_temp AS
SELECT row_number() OVER (ORDER BY id DESC) AS rn, id, title
FROM   mytable
WHERE  group_id = 10;

但索引和后续查询必须在行号rn上才能获取
以1000为一个区块的数据

CREATE INDEX ON mv_temp (**rn**);

SELECT * FROM mv_temp WHERE **rn** BETWEEN 1000 AND 2000;

您的实现将需要一个保证无间隙的id列-这将不需要添加以...开始的行号。
完成时:

DROP MATERIALIZED VIEW mv_temp;

索引会随表(在本例中为示例化视图)一起自动消失。
相关,详细信息:

  • 使用OFFSET优化大表查询
ygya80vv

ygya80vv2#

您希望查询前1000行,然后查询下1000行,依此类推?
通常您只需编写一个查询(您已经使用的查询),让您的应用获取1000条记录,对它们执行一些操作,然后获取下一个1000条记录,以此类推。
但是,编写这样的部分查询会相当容易:

select *
from
(
  SELECT id, row_number() over (ORDER BY id desc) AS rn, title
  FROM mytable
  WHERE group_id = 10
) numbered
where rn between 1 and 1000; -- <- simply change the row number range here
                             --    e.g. where rn between 1001 and 2000 for the second chunk
oxf4rvwz

oxf4rvwz3#

你需要分页试试这个

SELECT id, row_number() over (ORDER BY id desc)+0 AS row_number, title
FROM mytable
WHERE group_id = 10 AND id >= 0 AND id < 1000
ORDER BY id ASC;

下一次,当您在WHERE子句中更改id的起始值时,也可以在row_number()中更改它,如下所示

SELECT id, row_number() over (ORDER BY id desc)+1000 AS row_number, title
FROM mytable
WHERE group_id = 10 AND id >= 1000 AND id < 2000
ORDER BY id ASC;

或更好的方法,您可以使用OFFSET和LIMIT方法进行分页https://wiki.postgresql.org/images/3/35/Pagination_Done_the_PostgreSQL_Way.pdf

dluptydi

dluptydi4#

最后我是这么做的:
首先创建一个临时实体化视图:

CREATE MATERIALIZED VIEW vw_temp AS SELECT id, row_number() over (ORDER BY id desc) AS rn, title
FROM mytable
WHERE group_id = 10;

然后定义索引:

CREATE INDEX idx_temp ON vw_temp USING btree(id);

现在,我可以非常快速地执行所有操作,并且使用编号行:

SELECT * FROM vw_temp WHERE id BETWEEN 1000 AND 2000;

完成操作后,清理:

DROP INDEX idx_temp;
DROP MATERIALIZED VIEW vw_temp;

尽管Thorsten Kettner的答案看起来是最简洁的,但由于太慢,它对我来说并不实用。感谢大家的贡献。对于那些对实际用例感兴趣的人,我使用它来向Sphinx索引器提供数据。

相关问题