-
-
Notifications
You must be signed in to change notification settings - Fork 521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Composite key cursor pagination is broken #1209
Comments
Interestingly this is the same technique used when you have a single column key but you want to order the result set by a column. Having a generic solution could be reused for both use cases. |
@billy1624 I am going to give this a try if you are not working on it already |
Hey @tyt2y3, please proceed |
@tyt2y3 @billy1624 -- Fetch the first page
SELECT * FROM users ORDER BY created_at,id LIMIT 10;
-- Fetch the next page
SELECT * FROM users
WHERE (created_at, id) > ("2022-02-02 01:10:11", 73618361)
ORDER BY created_at,id
LIMIT 10; I see this method of page turning is called "keyset pagination" |
@holmofy This is not enough, you have to deal with the case where the order column is equal and nulls too. The document you link is a good resource though. Cursor pagination is very hard to get right especially multi-column |
Postgresql's Composite Type Comparison can support the case where the field is null, as the documentation says:
|
In addition, I feel that the KeySetPagination API of ActiveRecord in the gitlab link is very elegant |
Description
The SQL generated by the
Cursor
struct when using composite keys is incorrect and leads to missed results when paginating. The problem is that the WHERE clause is incorrect, it can only currently work if it just so happens that your two columns naturally followed the exact same ordering.Example
Lets say you have the following table:
Now lets say you want to paginate by category, category isn't unique so in order to page you need to combine with the ID column into a unique composite key.
The SQL to fetch the first page would look like:
Lets query the first 3 results:
Which returns:
Now we want to get the next page, according to the current implementation this creates a query like:
But this is wrong - we would end up only getting two more results, missing out many inbetween
We need to actually have a query like:
which produces:
Three Columns
Lets say you have 3 columns "x", "y", "z", then the WHERE clause needs to look like:
Versions
Present in master
Related To
@tyt2y3 @billy1624 @Sytten @ikrivosheev
The text was updated successfully, but these errors were encountered: