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

是否可以在不知道要排序的任何字段的情况下每次选择不同的行?

如何解决是否可以在不知道要排序的任何字段的情况下每次选择不同的行?

我有一个查询,比方说 X_QUERY,这个查询可以是任何东西(我们不知道任何字段)并且可以有 1 亿行。我需要将结果分成最多 16 个块,因此每个块都有 完全不同的 X_QUERY 行。我们可以假设在此过程中任何表都没有更新。

我在 oracle 中使用 ROWID 作为 order by 子句解决了同样的问题,所以我尝试在 Postgres 中使用 CTID,但没有奏效。

SELECT * 
FROM (X_QUERY) as origin ORDER BY ctid -- <-- ctid does not exist here
limit 6250000 offset 0; -- <-- next offsets should be 6250000,12500000 etc.

理想情况下,我想避免 order by 的额外成本,但我没有找到任何其他方法(至少使用 Oracle)。

那么,有没有办法避免某种顺序?
如果没有,有没有办法在不知道要排序的任何字段的情况下每次选择不同的行?

解决方法

这是我查看 SQL 游标 的少数情况之一。 The manual on DECLARE

DECLARE 允许用户创建游标,该游标可用于从较大的查询中一次检索少量行。

它不关心底层的排序顺序,并按照查询产生的顺序返回行。

使用 FETCH 获取下一组行。

示例:

BEGIN;
DECLARE x_cursor CURSOR FOR <X_QUERY>;  -- your query string here

FETCH 6250000 FROM x_cursor;
FETCH 6250000 FROM x_cursor;
FETCH 6250000 FROM x_cursor;
-- repeat until no more rows;

-- CLOSE x_cursor;  -- optional
COMMIT;
-- or ROLLBACK;  -- does not make a difference in this case

除非您声明 corsor WITH HOLD,否则必须在事务中完成所有操作。 The manual

除非指定了WITH HOLD,否则此命令创建的游标 只能在当前事务中使用。因此,DECLARE 没有 WITH HOLD 在事务块之外是无用的:游标 只会在语句完成后继续存在。所以 如果这样的命令在外部使用,PostgreSQL 会报告错误 交易区块。使用 BEGINCOMMIT(或 ROLLBACK)来定义 一个交易块。

如果您的查询是字符串,您可以在 PL/pgSQL 函数或 DO 语句中使用动态 SQL 来动态创建 SQL 游标 (WITH HOLD?) ,或使用 PL/pgSQL cursor 开头(相关但独立的实现)。


我曾尝试在 postgres 中使用 CTID,但没有奏效。

这是因为 ctid 是标识元组物理位置的系统列。除非在 SELECT 列表中明确列出,否则它不会包含在查询结果中。因此,它通常不在给定查询的结果中,并且在派生表中不一定是唯一的。因此,ctid 可用于在没有并发写入的情况下遍历表,但这不符合您的目的。
更多血腥细节:

,

您可以向 X_QUERY 添加一个名为 row_number() 的窗口函数。

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