I use PostgreSQL 12 to store my raw data and ElasticSearch as the datawarehouse for reports.

It happens that there are situations with JOIN (eg, data that exists in one table but does not exist in another) ElasticSearch not attending me, having to make queries that return a large number of results directly in PostgreSQL.

Many years ago I worked with a SELECT <column1, column2> FROM <table> WHERE <conditions>; totally without LIMIT or OFFSET, this caused my database to have a high load, taking up a lot of memory to return the results and my web server couldn't handle the amount of data that was returned, crashing (memory limit overflow, for example).

To solve this, I started working with a paging system, bringing in a limited number of records and paging the results with LIMIT and a condition to display the records below the last record of the previous query.


-- 1st Query
SELECT <column1, column2> FROM <table> WHERE <conditions> LIMIT 512;
-- 2nd Query
SELECT <column1, column2> FROM <table> WHERE <conditions> AND id < last_id_query_1 LIMIT 512;
-- 3rd Query
SELECT <column1, column2> FROM <table> WHERE <conditions> AND id < last_id_query_2 LIMIT 512;

In my opinion this method does not seem to be very good. Reading about CURSORS it seems that it does something similar, but using only one search. And several sites say that it performs much better than LIMIT/OFFSET.

Is this kind of statement true or is the current way I work also good?

As I cannot perform an EXPLAIN ANALYZE at each FETCH of the CURSOR, I have no way of actually analyzing whether it is faster and has better performance.

  • You may need to add an "order by id desc" and then you should be good. I'm afraid a cursor might consume too much memory. Jan 27, 2022 at 20:32

1 Answer 1


What you are currently doing is key-set pagination (except you don't show the necessary ORDER BY to make it work correctly--I'm assuming it is really there). With many queries and with the appropriate index this can work very well. You mention some concerns about it, but without any details on those concerns it is hard to know how valid and/or addressable they are.

Both cursor and key-set pagination should be much more efficient than OFFSET/LIIMT when there are a large number of pages, but note that in your example there is no OFFSET. There is just a LIMIT and a key-set for where to start. In other words, OFFSET/LIMIT might be bad, but that is not what you are doing.

The nice thing about key-set pagination over server-side cursor pagination is that the state is entirely and efficiently managed by the client. If the client doesn't come back for the next page for two weeks (or ever), that is of no concern to the server. With a server-side cursor however, you need some mechanism to hold the database connection open between page visits, and reattach to it. You also need some mechanism to declare a cursor abandoned, lest they accumulate and consume an unbounded amount of resources.

auto_explain will still record plans for cursors, as long as it is closed cleanly, either by an explicit CLOSE or by COMMIT.

  • I forgot to put the ORDER BY I use in the example. But your explanation helped me a lot to understand the cons of using CURSOR. Thanks.
    – Tom
    Jan 28, 2022 at 4:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.