用于对多个字段进行键集分页的通用SQL谓词

用于对多个字段进行键集分页的通用SQL谓词,sql,sql-server,pagination,orientdb,keyset,Sql,Sql Server,Pagination,Orientdb,Keyset,高性能分页的常见解决方案是使用索引字段,从上一页的最后一个值开始每个新“页”。例如,对于这样的数据集(假设Category和ID是主键): 假设页面大小(相当小)为1,如果我们希望返回所有Red类别记录(假设按类别排序,ID): 这是因为通过分页,“keyset”只使用ID字段(如果ID是全局唯一的,它也可以在多个字段上工作,而事实并非如此) 但是,如果我想返回所有红色和蓝色记录(假设该表还包含其他类别),仍然一次返回一页(假设按类别排序,ID): 在PostgreSQL和其他一些语言中,有一种

高性能分页的常见解决方案是使用索引字段,从上一页的最后一个值开始每个新“页”。例如,对于这样的数据集(假设Category和ID是主键):

假设页面大小(相当小)为1,如果我们希望返回所有
Red
类别记录(假设按类别排序,ID):

这是因为通过分页,“keyset”只使用ID字段(如果ID是全局唯一的,它也可以在多个字段上工作,而事实并非如此)

但是,如果我想返回所有红色和蓝色记录(假设该表还包含其他类别),仍然一次返回一页(假设按类别排序,ID):

在PostgreSQL和其他一些语言中,有一种“行值”谓词语法支持这一点(假定按类别排序,ID):

它之所以有效,是因为在测试中,Category和ID都被视为单个复合值。但我没有使用PostgreSQL或支持“行值”的数据库。所以问题是,是否有一个替代解决方案可以解决这个问题(是否有2个或n个字段)?为了在多个变量字段上进行分页,我需要设置一个谓词,该谓词将始终在多字段排序顺序中查找“下一条记录”


PS:OFFSET/LIMIT或SKIP/LIMIT分页当然有效,但在大型数据集上两者都无效,这就是我尝试使用“keyset”分页的原因。

您始终可以使用谓词短语:

(x, y) > (a, b)
作为:

请注意,第一个前缀
x>=a
促进(但不能确保)该列上索引的使用。也就是说,它变成了一个“访问谓词”。第二个
x=a和y>b或x>a
过滤掉多余的行,实际上成为一个“过滤谓词”

这种措辞“tuple不等式”谓词的方式促进了索引的使用。但是,如果要比较3列、4列或更多列,它们会变得越来越复杂。

进一步展开,使用复合键进行键集分页的通用语法如下所示:

在哪里
(x>a)或
(x=a,y>b)或
(x=a,y=b,z>c)或
...

这不如
(x,y,z)>(a,b,c)
好,但您可以用自己选择的语言生成SQL。您可以遍历组合字段集,并扩展每个后续字段,以包括前面字段的
{field}={value}和

使用更复杂的谓词可以实现键集分页,但它的效率(在索引使用方面)不如PostgreSQL,因为有几个数据库没有实现“元组不平等”运算符。DB2、PostgreSQL、MariaDB、MySQL、H2和HyperSQL确实实现了它。您使用的是哪个数据库?MSSQL和OrientDBYes,我认为这在技术上是正确的。我使用了这种方法,但正如您所说,它有两个以上的列,变得相当复杂。但是“访问谓词“是新奇的——我必须使用它,看看查询优化器如何处理它。
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)
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)
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)
(x, y) > (a, b)
x >= a and (x = a and y > b or x > a)