分块查询中的全局行号
Global row numbers in chunked query
我想在我的结果集中包含一列 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 重新开始,但我希望它就像第一种情况一样是全局查询的一部分。有没有简单的方法可以做到这一点?
您想查询前 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
您需要分页。试试这个
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
最后我是这样做的:
首先我创建了一个临时物化视图:
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 索引器。
假设:
id
定义为 PRIMARY KEY
- 即 UNIQUE
和 NOT NULL
。否则您可能必须处理 NULL 值和/或重复项(关系)。
您在 table 上没有并发写入权限 - 或者您不关心拍摄快照后发生的情况。
一个MATERIALIZED VIEW
, like you demonstrate ,是个不错的选择。
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
上才能得到
data in chunks of 1000
CREATE INDEX ON mv_temp (<b>rn</b>);
SELECT * FROM mv_temp WHERE <b>rn</b> BETWEEN 1000 AND 2000;
您的实施将需要保证无间隙的 id
列 - 这将不需要添加行号以 ...
开头
完成后:
DROP MATERIALIZED VIEW mv_temp;
索引随 table(在本例中为物化视图)自动消失。
相关,更详细:
我想在我的结果集中包含一列 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 重新开始,但我希望它就像第一种情况一样是全局查询的一部分。有没有简单的方法可以做到这一点?
您想查询前 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
您需要分页。试试这个
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
最后我是这样做的:
首先我创建了一个临时物化视图:
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 索引器。
假设:
id
定义为PRIMARY KEY
- 即UNIQUE
和NOT NULL
。否则您可能必须处理 NULL 值和/或重复项(关系)。您在 table 上没有并发写入权限 - 或者您不关心拍摄快照后发生的情况。
一个MATERIALIZED VIEW
, like you demonstrate
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
上才能得到
data in chunks of 1000
CREATE INDEX ON mv_temp (<b>rn</b>);
SELECT * FROM mv_temp WHERE <b>rn</b> BETWEEN 1000 AND 2000;
您的实施将需要保证无间隙的 id
列 - 这将不需要添加行号以 ...
完成后:
DROP MATERIALIZED VIEW mv_temp;
索引随 table(在本例中为物化视图)自动消失。
相关,更详细: