Mi sono imbattuto in un problema simile e dopo un paio d'ore di sangue, sudore e lacrime, ho scoperto che la risposta richiede semplicemente l'aggiunta di un parametro.
Invece di
cursor = conn.cursor()
scrivi
cursor = conn.cursor(name="my_cursor_name")
o ancora più semplice
cursor = conn.cursor("my_cursor_name")
I dettagli sono disponibili su http://initd.org/psycopg/docs/usage.html#server-side-cursors
Ho trovato le istruzioni un po' confuse in quanto pensavo di dover riscrivere il mio SQL per includere "DECLARE my_cursor_name ...." e poi un "FETCH count 2000 FROM my_cursor_name" ma si scopre che psycopg fa tutto per te sotto il cappuccio se si sovrascrive semplicemente il parametro predefinito "name=None" durante la creazione di un cursore.
Il suggerimento sopra di usare fetchone o fetchmany non risolve il problema poiché, se si lascia il parametro name non impostato, psycopg tenterà per impostazione predefinita di caricare l'intera query nella ram. L'unica altra cosa di cui potresti aver bisogno (oltre a dichiarare un parametro name) è cambiare l'attributo cursor.itersize dal default 2000 a dire 1000 se hai ancora poca memoria.