Dovrai mettere in cache qualcosa da qualche parte, sia che usi il db per farlo con un cursore, sia che lo faccia esterno al db.
Tuttavia, se hai il pieno controllo del db e del suo schema, potresti fare un po 'di cache delle righe e delle età delle righe all'interno delle tabelle stesse.
Potresti incorporare un timestamp o una colonna del numero di versione nella tua tabella che ti aiuterebbe a ottenere un'istantanea ragionevole delle righe senza una transazione di lunga durata (cioè il cursore) di fronte a aggiornamenti costanti.
Quindi, è possibile utilizzare query separate per ogni pagina = N, ognuna delle quali fornisce lo stesso timestamp o il numero di versione per il sistema da utilizzare insieme nella clausola where, in modo tale che solo le informazioni valide da quel punto vengano restituite indipendentemente da quale numero di pagina viene richiesto e di nuove righe inserite.
Se vengono eliminate anche le righe, dovrai lasciarle in posizione per conservare l'istantanea e semplicemente contrassegnarle come cancellate da quando / quale versione; un confronto di eliminazione sarebbe quindi utilizzato anche in congiunzione nella clausola where. (Puoi creare una vista da utilizzare per tutti gli altri scopi che omettono le righe cancellate.)
Se le eliminazioni vengono solo contrassegnate e non effettivamente eseguite, avresti una fonte di "perdita di memoria", ma potrebbe essere meglio che non eseguire i cursori. (Potresti desiderare una qualche forma di "GC" per pulire regolarmente le vecchie eliminazioni, supponendo che non vuoi supportare tornare indietro nel tempo.)
Se anche le righe vengono modificate, stai entrando abbastanza in profondità, ma potrebbe essere gestita eliminando (ovvero contrassegnando cancellato) l'originale e aggiungendo una nuova riga come sostituto. (La tua chiave primaria diventerà un problema che deve essere affrontato in qualche modo poiché avrai effettivamente duplicati).
Alcuni problemi potrebbero essere risolti avendo una tabella alternativa o duplicata con la colonna timestamp / versione # e rilassando alcuni vincoli su quella tabella. Le query di lunga durata utilizzerebbero quella tabella alternativa; gli aggiornamenti transazionali userebbero la tabella originale e ci sarebbe un meccanismo per alimentarne uno dall'altra.
Fondamentalmente, questa sarebbe la versione manuale / poorman dell'isolamento dello snapshot. Potrebbe essere meglio usare i cursori ... e terminare quelli troppo longevi.