Anti-pattern : OFFSET profond — passer au keyset
OFFSET 20000 lit et jette 20 000 lignes à chaque page. La pagination keyset (seek) repart du dernier élément vu : coût constant quelle que soit la profondeur.
Cas d'usage
Pagination d'API ou de back-office sur des tables volumineuses, scroll infini.
Prérequis
Index sur les colonnes de tri (created_at DESC, id DESC)
SQL
-- Anti-pattern : la page 1000 lit 20 020 lignes pour en garder 20
SELECT * FROM products
ORDER BY created_at DESC, id DESC
LIMIT 20 OFFSET 20000;
-- Correctif : keyset — on repart du dernier élément de la page précédente
SELECT * FROM products
WHERE (created_at, id) < ('2026-06-01 12:34:56', 18432)
ORDER BY created_at DESC, id DESC
LIMIT 20;
-- Le tuple (created_at, id) garantit un ordre total même à timestamp égalRésultat
id | created_at | name -------+---------------------+----------- 18431 | 2026-06-01 12:31:08 | Produit A 18419 | 2026-06-01 12:18:55 | Produit B 18402 | 2026-06-01 11:59:02 | Produit C (20 rows) -- OFFSET 20000 : Execution Time: 412.480 ms (lit 20 020 lignes) -- Keyset : Execution Time: 0.524 ms (lit 20 lignes)
SQLPaginationKeysetPerformance