Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

iterador/gerador SqlAlchemy embutido com eficiência de memória?


A maioria das implementações de DBAPI armazenam completamente as linhas à medida que são buscadas - portanto, geralmente, antes que o SQLAlchemy ORM obtenha 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 a você 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, caso contrário, coleções e tal pode ser apenas parcialmente preenchido.

Então Query oferece uma opção para alterar esse comportamento por meio de yield_per() . Esta chamada fará com que a Query para produzir linhas em lotes, onde você fornece o tamanho do lote. Como os documentos afirmam, isso só é apropriado se você não estiver fazendo nenhum tipo de carregamento antecipado de coleções, então é basicamente se você realmente sabe o que está fazendo. Além disso, se o DBAPI subjacente pré-buffers linhas, ainda haverá essa sobrecarga de memória, de modo que a abordagem só escala um pouco melhor do que não usá-la.

Eu quase nunca uso yield_per(); em vez disso, uso uma versão melhor da abordagem LIMIT sugerida acima usando funções de janela. LIMIT e OFFSET têm um grande problema de que valores OFFSET muito grandes 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 quero selecionar. Em seguida, emito instruções SELECT individuais que são extraídas de uma dessas janelas por vez.

A abordagem da função de janela está no wiki e eu o 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 o Postgresql definitivamente vale a pena - se você estiver usando um banco de dados relacional, também poderá usar o melhor.