Efficient Pagination In Postgresql (Keyset Pagination)
3
votes
1
answer
934
views
I'm working on implementing pagination for a PostgreSQL database in which I have a table that stores users for my application. I have a query that is intended to fetch the next page of users based on their forename and creation timestamp. However, I'm encountering some difficulties and would appreciate some guidance.
Types for the columns:
userId (string and stores uuidv5),
userForename (string),
userCreatedAt (timestamp)
Here's the query I'm using for fetching the next page:
is just a placeholder
SELECT "userId", "userForename", "userCreatedAt"
FROM iatropolis."User"
WHERE
LOWER("userForename") > 'aaliyah'
OR (LOWER("userForename") = 'aaliyah' AND
"userCreatedAt" > TIMESTAMP '2024-03-25 14:50:39.481197')
ORDER BY "userForename" ASC, "userCreatedAt" ASC
LIMIT ;
The goal of this query is to retrieve the first user after 'aaliyah' alphabetically, and if there are multiple users with the same forename, to select the one with a creation timestamp later than '2024-03-25 14:50:39.481197'.
However, I'm unsure if this query is correctly achieving the desired pagination. Even though I tested it and it outputted correct results, I don't know if it will behave in the long run as desired (not sure if I am missing something).
I have also tried to go to the previous page buy creating a similar query.
SELECT "userId", "userForename", "userCreatedAt"
FROM iatropolis."User"
WHERE
LOWER("userForename") ;
This is some ascending random data that I am working with:
| userId | userForename | userCreatedAt |
| ------------------------------------ | ------------ | -------------------------- |
| 38ee48f9-6d79-5690-9e51-df4b1cc5d428 | Aaliyah | 2024-03-25 14:50:39.481197 |
| ba2c1a86-280d-573f-ad35-ed1d023e3e5d | Aaliyah | 2024-03-25 14:51:35.52505 |
| 4f40dd7a-8f0f-54e4-bf14-3de3626bde67 | Abagail | 2024-03-25 19:27:10.985665 |
| e7b68316-188d-509e-9fd3-7fc780986c71 | Abbey | 2024-03-25 17:45:43.584704 |
| 1084f33e-9183-501d-b1af-70d61f1479d7 | Abbigail | 2024-03-25 19:27:29.720356 |
| 561e71fd-f04a-54d2-9864-2324e28cdfbd | Abbigail | 2024-03-25 19:27:35.5478 |
| ab5ad018-1866-50a4-8bf6-568f74988d21 | Abbigail | 2024-03-25 17:46:35.309003 |
| 596e13f2-e413-5b50-bdfb-9e68f0edf3db | Abdiel | 2024-03-25 17:47:08.576102 |
| d0d5bff9-f782-5451-bda4-e4d4a3e49f04 | Abdiel | 2024-03-25 14:51:24.257638 |
| 33a02ded-b354-5a6b-b506-cad3595d19be | Abdul | 2024-03-25 17:46:49.809666 |
| 6e1f68ff-f799-511e-ba91-83b35349e652 | Abdul | 2024-03-25 14:51:02.533247 |
| f67226da-a560-5913-9770-c23499046dc5 | Abe | 2024-03-25 14:49:34.342507 |
| 4e345a84-144d-55e2-a568-ce2064cb91fc | Abigale | 2024-03-25 19:26:32.349998 |
| ecab4167-8275-5c45-a6ce-5f616edeb60b | Abigale | 2024-03-25 19:26:24.406462 |
| 3689dc88-b57c-572b-90cd-3bd0c4603656 | Abigayle | 2024-03-25 14:50:41.608976 |
| db26cecb-0532-5cd4-b45e-04c14ce48b97 | Abigayle | 2024-03-25 19:26:54.081197 |
| 03d9e144-ba2e-5d08-b8bc-abaa42b59848 | Abner | 2024-03-25 17:47:12.313267 |
| e7d3fd8b-9187-5e78-8178-93eef85c3edc | Abner | 2024-03-25 19:27:35.016205 |
| 3a0c5db0-a19b-57b2-be99-6c0e0d33fb4c | adadadFN | 2024-03-22 11:33:03.466138 |
| daada509-45b3-58e8-920f-2441395af0f8 | Adalberto | 2024-03-25 17:46:31.150524 |
| dd3781a8-45ae-5ecb-9d5d-b4230347b0d8 | Adaline | 2024-03-25 17:46:05.821796 |
| c2122ddb-fd31-59ea-b5db-3e8696f0a2fc | Adan | 2024-03-25 14:51:06.880816 |
| 19ac3589-47ac-53ba-8e8c-c1537babbe97 | Addie | 2024-03-25 17:47:04.303399 |
| c61c8d3a-02b7-5db3-8b84-dba2fbf522b8 | Addie | 2024-03-25 17:46:35.627732 |
| 6800cc09-113a-5383-a9ec-463bfeb1f3aa | Addison | 2024-03-25 17:46:24.314788 |
This is some descending random data that I am working with:
| userId | userForename | userCreatedAt |
| ------------------------------------ | ------------ | -------------------------- |
| d64ce86e-1bf4-56d8-86dc-e0ffd9bae972 | Zula | 2024-03-25 14:51:53.062856 |
| e6f98b6c-ae16-58e9-ba3a-979dac63058d | Zora | 2024-03-25 17:46:15.697886 |
| 951b1493-0f86-5741-8b3d-5b7db7466f25 | Zora | 2024-03-25 14:51:38.315643 |
| a2c4455e-5333-57ea-9e7e-6a8ca03a7cf4 | Zita | 2024-03-25 19:26:44.119388 |
| d00c4951-de6a-5290-b956-13bf3b3e11eb | Zita | 2024-03-25 14:51:28.445206 |
| 390b6dae-b47e-57d7-8a7f-10a002d9b3a3 | Zion | 2024-03-25 14:50:18.578468 |
| 6f6371a0-b5bd-5839-aed2-81e8b8e0bff7 | Zetta | 2024-03-25 19:27:22.998847 |
| 4750df40-ffda-55e2-b26b-7c0c2ecf87e5 | Zetta | 2024-03-25 19:26:01.682206 |
| 14d137e7-83aa-5463-b47e-1a2376b53376 | Zelma | 2024-03-25 14:50:15.690687 |
| 0defcb46-486c-5273-9c81-e553500de614 | Zelma | 2024-03-25 14:49:32.577772 |
| 1a28a48b-bc3b-5f84-bbae-1ac0839bf311 | Zechariah | 2024-03-25 19:26:04.410123 |
| 574bf44e-2604-5ff1-95a9-164287d3c880 | Zane | 2024-03-25 19:27:15.455109 |
| e7b0e413-2eff-5240-8c18-321664a42416 | Zander | 2024-03-25 19:26:45.864325 |
| 2a737734-2c45-54c0-b911-315c8d333884 | Zakary | 2024-03-25 14:50:34.264419 |
| 782ddfaa-df67-50e3-841d-fa21b525e75c | Zackery | 2024-03-25 17:47:17.542445 |
| d24c75f2-7152-50aa-96ef-3a2d3847f1d3 | Zackary | 2024-03-25 17:46:58.029806 |
| c2d6d8c5-3891-57fb-bbea-57e22cb51da4 | Zack | 2024-03-25 17:46:27.203011 |
| 3333d2de-8028-5f00-8e4c-db821e8fe1a5 | Zachary | 2024-03-25 17:46:25.890929 |
| f11dfc68-78f1-5290-b203-9e04449c0538 | Zachary | 2024-03-25 14:50:27.447767 |
| d88c05bc-5fe4-5597-94b5-ca29c99a2df4 | Zachariah | 2024-03-25 17:46:52.98815 |
| cf8e2a99-e308-53ae-8908-8c2ff0188143 | Zachariah | 2024-03-25 14:51:47.465403 |
| da1ed730-9965-56c2-9317-e1726f172afc | Yvonne | 2024-03-25 19:26:36.714501 |
| 97a4213a-5fd5-5d0d-a860-567295ab9a23 | Yvonne | 2024-03-25 14:51:20.7755 |
| 41ce8c6b-5cca-57b9-a74b-d9fbf8f32ade | Yvette | 2024-03-25 14:50:18.973821 |
| 9f47693b-bcfd-5e2c-b92f-56aefb79ce03 | Yoshiko | 2024-03-25 19:27:33.647082 |
My question is somebody that knows SQL properly and used it for years and years, would agree that this keyset pagination is implemented properly? Also, for my case, being able to order the columns is very important, this being the reason of why I included the userForename in the queries. In the event that my queries are not correct, could somebody show me how to do them properly? Additionally, I am open to exploring alternative approaches if there are more efficient solutions available.
Asked by odyssey
(33 rep)
Mar 25, 2024, 07:09 PM
Last activity: Feb 10, 2025, 10:02 AM
Last activity: Feb 10, 2025, 10:02 AM