使用 joinload 的 sqlalchemy 查询对于每个新的过滤子句会呈指数减慢

Aug*_*nha 1 python sqlalchemy

我有这个 sqlalchemy 查询:

query = session.query(Store).options(joinedload('salesmen').
                                        joinedload('comissions').
                                        joinedload('orders')).\
        filter(Store.store_code.in_(selected_stores))

stores = query.all()
for store in stores:
    for salesman in store.salesmen:
        for comission in salesman.comissions:
            #generate html for comissions for each salesman in each store

#print html document using PySide
Run Code Online (Sandbox Code Playgroud)

这工作得很好,但是我添加了两个新的过滤器查询:

        filter(Comissions.payment_status == 0).\
        filter(Order.order_date <= self.dateEdit.date().toPython())
Run Code Online (Sandbox Code Playgroud)

如果我只添加第一个过滤器,应用程序会挂起几秒钟,如果我添加两个过滤器,应用程序会无限期挂起

我在这里做错了什么?如何快速进行此查询?

感谢您的帮助

编辑:这是生成的sql,不幸的是类和变量名称是葡萄牙语的,我只是将它们翻译成英语,这样会更容易理解,所以Loja = Store,Vendores = Salesmen,Pedido = Order,Commission = Comissao

生成的查询:

SELECT "Loja"."CodLoja", "Vendedores_1"."CodVendedor", "Vendedores_1"."NomeVendedor", "Vendedores_1"."CodLoja", "Vendedores_1"."PercentualComissao", 
"Vendedores_1"."Ativo", "Comissao_1"."CodComissao", "Comissao_1"."CodVendedor", "Comissao_1"."CodPedido", 
"Pedidos_1"."CodPedido", "Pedidos_1"."CodLoja", "Pedidos_1"."CodCliente", "Pedidos_1"."NomeCliente", "Pedidos_1"."EnderecoCliente", "Pedidos_1"."BairroCliente", 
"Pedidos_1"."CidadeCliente", "Pedidos_1"."UFCliente", "Pedidos_1"."CEPCliente", "Pedidos_1"."FoneCliente", "Pedidos_1"."Fone2Cliente", "Pedidos_1"."PontoReferenciaCliente",
 "Pedidos_1"."DataPedido", "Pedidos_1"."ValorProdutos", "Pedidos_1"."ValorCreditoTroca", 
"Pedidos_1"."ValorTotalDoPedido", "Pedidos_1"."Situacao", "Pedidos_1"."Vendeu_Teflon", "Pedidos_1"."ValorTotalTeflon", 
"Pedidos_1"."DataVenda", "Pedidos_1"."CodVendedor", "Pedidos_1"."TipoVenda", "Comissao_1"."Valor", "Comissao_1"."DataPagamento", "Comissao_1"."StatusPagamento" 
FROM "Comissao", "Pedidos", "Loja" LEFT OUTER JOIN "Vendedores" AS "Vendedores_1" ON "Loja"."CodLoja" = "Vendedores_1"."CodLoja" 
LEFT OUTER JOIN "Comissao" AS "Comissao_1" ON "Vendedores_1"."CodVendedor" = "Comissao_1"."CodVendedor" LEFT OUTER JOIN "Pedidos" AS "Pedidos_1" ON "Pedidos_1"."CodPedido" = "Comissao_1"."CodPedido" 
WHERE "Loja"."CodLoja" IN (:CodLoja_1) AND "Comissao"."StatusPagamento" = :StatusPagamento_1 AND "Pedidos"."DataPedido" <= :DataPedido_1
Run Code Online (Sandbox Code Playgroud)

Mat*_*ohn 5

您的FROM子句正在生成笛卡尔积,并包含每个表两次,一次用于过滤结果,一次用于急切加载关系。

要停止此操作,请在选项中使用contains_eager而不是 joinload 。这将在查询的列中查找相关属性,而不是构造额外的联接。您还需要显式联接到查询中的其他表,例如:

query = session.query(Store)\
               .join(Store.salesmen)\   
               .join(Store.commissions)\    
               .join(Store.orders)\     
               .options(contains_eager('salesmen'),
                        contains_eager('comissions'),
                        contains_eager('orders'))\
               .filter(Store.store_code.in_(selected_stores))\
               .filter(Comissions.payment_status == 0)\
               .filter(Order.order_date <= self.dateEdit.date().toPython())
Run Code Online (Sandbox Code Playgroud)