I have a Heroku app that uses a psycopg server-side cursor together with a LEFT JOIN
query running on Heroku PG 13.5.
The query basically says “fetch items from one table, that don’t appear in another table”.
My data volume is pretty stable, and this has been working well for some time.
This week these queries stopped returning. In pg_stat_activity
they appeared as active
indefinitely (17+ hours), similarly in heroku pg:ps
. There appeared to be no deadlocks. All the Heroku database metrics and logs appeared healthy.
If I run the same queries directly in the console (without a cursor) they return in a few seconds.
I was able to get it working again in the cursor by making the query a bit more efficient (switching from LEFT JOIN
to NOT EXISTS
; dropping one of the joins).
My questions are:
I can say that:
LEFT JOIN
, Subquery, NOT EXISTS
), the query plan involves a Nested Loop Anti JoinAny advice appreciated!
If you are using a cursor, PostgreSQL estimates that only 10% of the query result will be fetched quickly and prefers plans that return the first few rows quickly, at the expense of the total query cost.
You can disable this optimization by setting the PostgreSQL parameter cursor_tuple_fraction
to 1.0.