Couchbase N1QL OFFSET pagination for large datasets with non-unique sort keys
0 reputation · 16 Nov 2024, 18:47 UTC
0 reputation · 16 Nov 2024, 18:47 UTC
Pagination for a large Couchbase dataset is commonly implemented with N1QL ORDER BY, LIMIT, and OFFSET clauses. When the sort attribute is not guaranteed to be unique, each page boundary can become unstable if documents are inserted, updated, or deleted between requests. Large OFFSET values also require the engine to scan and discard preceding rows, which raises latency as the page number grows.
The goal is to bound the result set predictably while keeping the query plan efficient. It is unclear whether N1QL provides a documented mechanism to make OFFSET-based paging stable when the sort key is non-unique, or whether the only supported approach is to switch to keyset pagination with a unique indexed attribute. Version-specific behavior across Couchbase Server 7.x and later also needs confirmation.
Can OFFSET pagination be made deterministic with a non-unique ORDER BY key in current N1QL? Is there a documented performance threshold where OFFSET should be abandoned in favor of keyset filters? What index configuration is required to make either approach efficient for deep paging?
33275 reputation · 16 Nov 2024, 21:54 UTC
Determinism: OFFSET pagination cannot be made stable with a non-unique ORDER BY key alone in current N1QL. Rows with equal sort values can be returned in different relative order across executions, so page boundaries drift with inserts, updates or deletes.
Performance threshold: No official hard OFFSET limit is published for Couchbase Server 7.x+. Performance degrades with offset depth because the engine must scan and discard preceding rows. Couchbase guidance favors keyset pagination for deep paging rather than growing OFFSET.
Index requirement: Efficient paging requires an index whose key prefix matches the ORDER BY columns in the same order, with WHERE predicates covered when possible. For keyset pagination the index must include the sort columns plus the unique tie-breaker used in the continuation filter.
ORDER BY sort_key, META().id. Adding a unique tie-breaker removes non-determinism for ties. This is a general ordering property, not an OFFSET-specific feature.Change the query to include a unique tie-breaker:
SELECT ... FROM bucket
WHERE ...
ORDER BY sort_key ASC, META().id ASC
LIMIT 20 OFFSET ?
For keyset pagination replace OFFSET with a continuation filter:
SELECT ... FROM bucket
WHERE ... AND (sort_key > $last_sort_key OR sort_key = $last_sort_key AND META().id > $last_id)
ORDER BY sort_key ASC, META().id ASC
LIMIT 20
Create or verify an index that starts with the sort columns in the same order as ORDER BY, followed by the tie-breaker:
CREATE INDEX ix_paging ON bucket(sort_key ASC, META().id ASC)
WHERE ...
If filters are used, include them before the sort prefix or make the index covering.
EXPLAIN on the paginated query to confirm index usage and that ORDER BY is satisfied by the index prefix.One missing diagnostic detail that changes the recommendation: the exact Couchbase Server version and the current index definition used for the query. Planner behavior and covering index support are version-sensitive, and the index must be rebuilt if META().id is added to ORDER BY.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.