Reputation: 37095
Suppose I have a table of events with (indexed) columns id : uuid
and created : timestamp
.
The id
column is unique, but the created
column is not. I would like to walk the table in chronological order using the created
column.
Something like this:
SELECT * FROM events WHERE created >= $<after> ORDER BY created ASC LIMIT 10
Here $<after>
is a template parameter that is taken from the previous query.
Now, I can see two issues with this:
created
is not unique, the order will not be fully defined. Perhaps the sort should be id, created
? How should I go about this in Postgres?
Upvotes: 4
Views: 3259
Reputation: 12432
SELECT * FROM events
WHERE created >= $<after> and (id >= $<id> OR created > $<after>)
ORDER BY created ASC ,id ASC LIMIT 10
that way the events each timestamp values will be ordered by id. and you can split pages anywhere.
you can say the same thing this way:
SELECT * FROM events
WHERE (created,id) >= ($<after>,$<id>)
ORDER BY created ASC ,id ASC LIMIT 10
and for me this produces a slightly better plan.
An index on (created,id)
will help performance most, but for
many circumstances an index on created
may suffice.
Upvotes: 13
Reputation: 311978
First, as you said, you should enforce a total ordering. Since the main thing you care about is created
, you should start with that. id
could be the secondary ordering, a tie breaker invisible to the user that just ensures the ordering is consistent. Secondly, instead of messing around with conditions on created
, you could just use an offset
clause to return later results:
SELECT * FROM events ORDER BY created ASC, id ASC LIMIT 10 OFFSET <10 * page number>
-- Note that page number is zero based
Upvotes: 0