A maioria das implementações DBAPI armazena totalmente as linhas à medida que são buscadas - então, normalmente, antes que o SQLAlchemy ORM consiga um resultado, todo o conjunto de resultados está na memória.
Mas então, a maneira como Query
funciona é que ele carrega totalmente o conjunto de resultados fornecido por padrão antes de retornar seus objetos. A lógica aqui diz respeito a consultas que são mais do que simples instruções SELECT. Por exemplo, em junções a outras tabelas que podem retornar a mesma identidade de objeto várias vezes em um conjunto de resultados (comum com carregamento antecipado), o conjunto completo de linhas precisa estar na memória para que os resultados corretos possam ser retornados de outra forma, coleções e tal pode ser apenas parcialmente preenchido.
Portanto, Query
oferece uma opção para alterar esse comportamento por meio yield_per()
. Essa chamada fará com que o Query
produza linhas em lotes, onde você fornece o tamanho do lote. Como afirma a documentação, isso só é apropriado se você não estiver fazendo nenhum tipo de carregamento antecipado de coleções, portanto, basicamente, se você realmente souber o que está fazendo. Além disso, se as linhas de pré-buffer de DBAPI subjacentes, ainda haverá essa sobrecarga de memória, de modo que a abordagem é apenas um pouco melhor dimensionada do que não usá-la.
Eu quase nunca uso yield_per()
; em vez disso, uso uma versão melhor da abordagem LIMIT que você sugeriu acima, usando funções de janela. LIMIT e OFFSET têm um grande problema de que valores muito grandes de OFFSET fazem com que a consulta fique cada vez mais lenta, pois um OFFSET de N faz com que ela percorra N linhas - é como fazer a mesma consulta cinquenta vezes em vez de uma, cada vez lendo um número cada vez maior de linhas. Com uma abordagem de função de janela, eu pré-busco um conjunto de valores de "janela" que se referem a partes da tabela que desejo selecionar. Em seguida, emito instruções SELECT individuais, cada uma puxando de uma dessas janelas por vez.
A abordagem da função de janela está no wiki e eu a uso com grande sucesso.
Observe também: nem todos os bancos de dados suportam funções de janela; você precisa do Postgresql, Oracle ou SQL Server. IMHO usando pelo menos Postgresql definitivamente vale a pena - se você estiver usando um banco de dados relacional, você também pode usar o melhor.