该表有一个主键。好好利用它。
代替LIMIT
and OFFSET
,使用主键上的过滤器进行分页。您在评论中暗示了这一点:
使用随机数进行分页(在每个查询中添加“GREATER THAN ORDER BY”)
但是你应该怎么做并不是随机的。
SELECT * FROM big_table WHERE id > $1 ORDER BY id ASC LIMIT $2
允许客户端指定两个参数,它看到的最后一个 ID 和要获取的记录数。您的 API 必须有一个占位符、额外参数或替代调用“获取前n 个 ID”,其中省略了WHERE
查询中的子句,但这很简单。
这种方法将使用相当有效的索引扫描来按顺序获取记录,通常避免排序或遍历所有跳过的记录的需要。客户端可以决定一次需要多少行。
这种方法在一个关键方面与LIMIT
and方法不同OFFSET
:并发修改。如果您使用低于某些客户已经看到的键INSERT
的键进入表,这种方法根本不会改变其结果,而该方法将重复一行。同样,如果您的行 ID 低于已见过的 ID,则此方法的结果不会改变,而会跳过未见过的行。不过,生成键的仅追加表没有区别。OFFSET
DELETE
OFFSET
如果您事先知道客户端将需要整个结果集,那么最有效的做法就是将整个结果集发送给他们,而无需进行任何分页业务。那就是我会使用光标的地方。从数据库中读取行,并以客户端接受它们的速度将它们发送给客户端。此 API 需要设置客户端允许的速度限制,以避免过多的后端负载;对于慢速客户端,我可能会切换到分页(如上所述)或将整个游标结果假脱机到一个临时文件并关闭数据库连接。
重要警告:
- 需要
UNIQUE
约束/UNIQUE
索引或PRIMARY KEY
可靠
- 限制/偏移的不同并发修改行为,见上文