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

Is it possible to select different rows each time without knowing any fields to sort?

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

我在 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)。

那么,有没有办法避免某种顺序?
如果没有,有没有办法每次都select 不同的行不知道要排序的字段?

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

这是我会寻找 SQL 光标 的罕见情况之一。 The manual on DECLARE:

DECLARE allows a user to create cursors, which can be used to retrieve a small number of rows at a time out of a larger query.

它不关心底层排序顺序和查询生成它的序列中的 returns 行。

使用 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:

Unless WITH HOLD is specified, the cursor created by this command can only be used within the current transaction. Thus, DECLARE without WITH HOLD is useless outside a transaction block: the cursor would survive only to the completion of the statement. Therefore PostgreSQL reports an error if such a command is used outside a transaction block. Use BEGIN and COMMIT (or ROLLBACK) to define a transaction block.

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


I have tried using CTID in postgres, but did not work.

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