Entenda melhor os problemas do `yield_per ()` do SQLalchemy
CitarDocumentação SQLalchemy:
O método Query.yield_per () não é compatível com a maioria dos esquemas de carregamento ansiosos, incluindo subqueryload e joinload com coleções.
Aviso
Use este método com cuidado; se a mesma instância estiver presente em mais de um lote de linhas, as alterações do usuário final nos atributos serão substituídas.
Em particular, geralmente é impossível usar essa configuração com coleções carregadas avidamente (ou seja, qualquer preguiçoso = 'juntou-se' ou 'subconsulta'), pois essas coleções serão limpas para uma nova carga quando encontradas em um lote de resultados subsequente. No caso de carregamento de "subconsulta", o resultado completo de todas as linhas é buscado, o que geralmente anula o objetivo de yield_per ().
Observe também que, embora yield_per () defina a opção de execução stream_results como True, atualmente isso é entendido apenas pelo dialeto psycopg2, que transmite resultados usando cursores do lado do servidor em vez de pré-armazenar todas as linhas nesta consulta. Outros DBAPIs pré-protegem todas as linhas antes de disponibilizá-las. O uso de memória das linhas brutas do banco de dados é muito menor que o de um objeto mapeado pelo ORM, mas ainda deve ser levado em consideração ao fazer o benchmarking.
Eu realmente tenho um problema para entender comoyield_per()
funciona e qual é exatamente o problema ao usar esse método. Além disso, qual é a maneira correta de solucionar esses problemas e continuar usando essa função para iterar uma enorme quantidade de linhas.
Estou interessado em todas as informações construtivas que você possui, mas aqui estão algumas dicas:
Como pode haver várias instâncias da mesma linha? Somente através de relacionamentos (se duas linhas da tabela de iteração tiverem um FK para a mesma linha em outra tabela)? Existe um problema se você não sabe o que acontece ou apenas lê atributos nos relacionamentos?preguiçoso = 'ingressou' ou 'subconsulta' não é possível, mas por que exatamente? Ambos são simplesmente partes da sua consulta à qual você chamayield_per()
.Se eles forem limpos em um lote de resultados subsequente, basta carregá-lo novamente. Então onde está o problema? Ou é o único problema que você perde as mudanças de seus relacionamentos se elas fizeram mudanças?No caso de um carregamento de "subconsulta", por que todas as linhas são buscadas? O SQL Server pode precisar salvar uma tabela grande, mas por que não simplesmente retornar o resultado em lotes, um após o outro, para toda a consulta?Em um exemplo noyield_per()
doc q = sess.query(Object).yield_per(100).options(lazyload('*'), joinedload(Object.some_related))
eles desativam o ealoadload comlazyload('*')
mas mantenha uma única carga unida. Existe uma maneira de ainda usaryield_per()
com ansioso? Quais são as condições?Eles dizempsycopg2
é o único DBAPI que suporta resultados de fluxo. Assim é que o único DBAPI com o qual você pode usaryield_per()
? Tanto quanto eu entendoyield_per
usa ocursor.fetchmany()
(exemplo) função do DBAPI que suporta muitos deles. E até onde eu entendocursor.fetchmany()
suporta buscar apenas partes do resultado e não buscar tudo (se buscaria tudo, por que a função existe?)Eu tenho a sensação de queyield_per()
é totalmente seguro (mesmo com carga rápida) se você apenas tiver acesso de leitura (por exemplo, para estatísticas). Isso está correto?