SEEK子句
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
前面的章节讨论了使用 LIMIT .. OFFSET
或 OFFSET .. FETCH
或其他一些供应商特定的变体来进行 OFFSET 分页。 当达到较高的页码时,这可能会导致严重的性能问题,因为数据库需要跳过所有不需要的记录。
一种更快,更稳定的分页方法是所谓的键集分页方法,也称为查找方法。 jOOQ 支持一个合成的 seek()
子句,可用于执行键集分页(了解 其他合成 SQL 语法)。 假设我们有这些数据
+------+-------+---------------+ | ID | VALUE | PAGE_BOUNDARY | +------+-------+---------------+ | ... | ... | ... | | 474 | 2 | 0 | | 533 | 2 | 1 | <-- Before page 6 | 640 | 2 | 0 | | 776 | 2 | 0 | | 815 | 2 | 0 | | 947 | 2 | 0 | | 37 | 3 | 1 | <-- Last on page 6 | 287 | 3 | 0 | | 450 | 3 | 0 | | ... | ... | ... | +------+-------+---------------+
现在,如果我们想向用户显示第 6 页,我们可以只获取严格位于第 5 页最后一条记录之后的记录,而不是使用记录 OFFSET
转到第 6 页,这样会得到值 (533, 2)
。 以下是如何使用 SQL 或 jOOQ 来实现
SELECT id, value FROM t WHERE (value, id) > (2, 533) ORDER BY value, id LIMIT 5
DSL.using(configuration) .select(T.ID, T.VALUE) .from(T) .orderBy(T.VALUE, T.ID) .seek(lastValue, lastId) // from last page: value = 2, id = 533 .limit(5) .fetch();
如您所见,jOOQ SEEK
子句是一个合成子句,它在 SQL 中并不真正存在。 但是,由于多种原因,jOOQ 语法更直观
- 它替换了您期望的
OFFSET
- 它不会强迫您将常规谓词与“查找”谓词混合使用
- 它是类型安全的
- 它为您模拟行值表达式谓词,在那些不支持它们的数据库中
此查询现在产生
+-----+-------+ | ID | VALUE | +-----+-------+ | 640 | 2 | | 776 | 2 | | 815 | 2 | | 947 | 2 | | 37 | 3 | +-----+-------+
请注意,您不能将 SEEK
子句与 OFFSET
子句结合使用。
有关此强大功能的更多信息,请参见 jOOQ 博客
- https://blog.jooq.org/faster-sql-paging-with-jooq-using-the-seek-method/
- https://blog.jooq.org/faster-sql-pagination-with-keysets-continued/
有关 offset 分页与键集分页性能的更多信息,请访问我们的合作伙伴页面
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!