【发布时间】:2019-11-05 06:13:44
【问题描述】:
高性能分页的常见解决方案是使用索引字段,从前一页的最后一个值开始每个新“页”。例如,对于这样的数据集(假设 Category 和 ID 是主键):
Category | ID | Name
Red | 10 | Bob Jones
Red | 14 | Sam Smith
Red | 16 | Jill White
Blue | 10 | Mike Green
Blue | 16 | Mary Brown
假设(相当小的)页面大小为 1,如果我们想要返回所有 Red 类别记录(假设 ORDER BY Category, ID):
SELECT * FROM table WHERE Category='Red' AND ID>'00' (1st page, returns Bob Jones)
SELECT * FROM table WHERE Category='Red' AND ID>'10' (2nd page, returns Sam Smith)
SELECT * FROM table WHERE Category='Red' AND ID>'14' (3rd page, returns Jill White)
这是可行的,因为通过分页,“keyset”仅使用 ID 字段(如果 ID 是全局唯一的,它也可以在多个字段上工作,但事实并非如此)。
但是如果我想返回所有的 Red 和 Blue 记录(假设该表还包含其他 Categories),仍然是一次一页(假设 ORDER BY Category, ID):
SELECT * FROM table WHERE Category IN ['Red', 'Blue'] AND Category>'' AND ID>'00' (1st page, returns Bob Jones)
SELECT * FROM table WHERE Category IN ['Red', 'Blue'] AND Category>'Red' AND ID>'10' (2nd page, returns Sam Smith, but skips Mike Green)
在 PostgreSQL 和其他一些中,有一个“行值”谓词语法支持这一点(假设 ORDER BY Category, ID):
SELECT * FROM table WHERE (Category, ID) > ('', '00') (1st page, returns Bob Jones)
SELECT * FROM table WHERE (Category, ID) > ('Red', '10') (2nd page, returns Sam Smith)
之所以有效,是因为 Category 和 ID 在测试中都被视为单个复合值。但我没有使用 PostgreSQL 或支持“行值”的数据库。所以问题是是否有替代解决方案可以解决这个问题(是否有 2 个或 n 个字段)?为了让它在多个变量字段上进行分页,我需要设置一个谓词,该谓词将始终在多字段排序顺序中找到“下一条记录”。
PS:OFFSET/LIMIT 或 SKIP/LIMIT 分页当然可以,但在大型数据集上都没有效率,这就是我尝试使用“keyset”分页的原因。
【问题讨论】:
-
使用更复杂的谓词可以实现键集分页,但它不会像 PostgreSQL 那样高效(在索引使用方面),因为有几个数据库没有实现“元组不等式”操作员。不过,DB2、PostgreSQL、MariaDB、MySQL、H2 和 HyperSQL 确实实现了它。您使用的是哪个数据库?
-
MSSQL 和 OrientDB
标签: sql sql-server pagination orientdb keyset-pagination