I have a table I’m doing an ORDER BY on before a LIMIT and OFFSET in order to paginate.
Adding an index on the ORDER BY column makes a massive difference to performance (when used in combination with a small LIMIT). On a 500,000 row table, I saw a 10,000x improvement adding the index, as long as there was a small LIMIT.
However, the index has no impact for high OFFSETs (i.e. later pages in my pagination). This is understandable: a b-tree index makes it easy to iterate in order from the beginning but not to find the nth item.
It seems that what would help is a counted b-tree index, but I’m not aware of support for these in PostgreSQL. Is there another solution? It seems that optimizing for large OFFSETs (especially in pagination use-cases) isn’t that unusual.
Unfortunately, the PostgreSQL manual simply says “The rows skipped by an OFFSET clause still have to be computed inside the server; therefore a large OFFSET might be inefficient.”
You might want a computed index.
Let’s create a table:
And fill it with some random stuff:
Index it by day, nothing special here:
Create a row position function. There are other approaches, this one is the simplest:
Check if it works (don’t call it like this on large datasets though):
Now the tricky part: add another index computed on the sales_pos function values:
Here is how you use it. 5 is your “offset”, 10 is the “limit”:
It is fast, because when you call it like this, Postgres uses precalculated values from the index:
Hope it helps.