[pyar] [django] Consulta en tabla grande con annotate y Sum

Matias Varela matu.varela en gmail.com
Mie Dic 17 11:07:02 ART 2014


El 06/12/14 12:30, Ariel Rossanigo escribió:
> +1 a lo que dice Juan Carlos, las 3 queries son distintas. Fijate que
> por ejemplo la 1 y 2 no tienen el limite de la cantidad de clientes.
>
> Ademas de que las queries son distintas, la forma de tratar los datos
> en Python es distinta.
> La 1 genera una lista de diccionarios, la 2 una lista de objetos y la
> tercera una lista de tuplas.
>
> La 3er opción es la más rápida porque trae solo 3000 clientes y además
> no tiene el overhead de generar objetos.
>
> ¿Vos necesitas los clientes aún cuando el saldo es 0? 
> Si es así tenes que partir de "Cliente" como proponías inicialmente y
> ver donde radica el problema de performance. Si en la base de datos
> está todo medianamente bien hecho, el motor solo debiera elegir si le
> conviene hacer un barrido de la tabla de movimientos o no. Esto lo
> podes ver  en el plan de ejecucion del motor (copias la query que
> genera el ORM, vas a psql y la ejecutas anteponiendo EXPLAIN o, si se
> puede por cuestiones de tiempo, EXPLAIN ANALYZE). Si necesitas una
> mano con esto ultimo copia el resultado en [0] y pasame el link.
>
> Además de esto, si vas a tener 8M de movimientos y la consulta la vas
> a ejecutar periodicamente, te convendría investigar si tenes bien
> "tuneada" la db. Igual esto ya es medio OT... 
>
> Saludos
> Ariel
>
> [0]: http://explain.depesz.com/ 
Buenos días!

Sigo con este tema. Definitivamente necesito un QuerySet de esto, ya que
usamos django-tables2 y django-filter que esperan un QuerySet.
Entonces, la consulta la hago así:

    queryset = Cliente.objects.annotate(saldo=Sum('movimientos__monto'))

En la db:

SELECT
"core_cliente"."id", "core_cliente"."creado_el",
"core_cliente"."modificado_el",
"core_cliente"."nombre", "core_cliente"."apellido",
"core_cliente"."fecha_nacimiento",
"core_cliente"."genero", "core_cliente"."estado_civil",
"core_cliente"."dni",
"core_cliente"."domicilio", SUM("core_movimientocliente"."monto") AS
"saldo"
FROM "core_cliente"
LEFT OUTER JOIN "core_movimientocliente" ON ( "core_cliente"."id" =
"core_movimientocliente"."cliente_id" )
GROUP BY "core_cliente"."id", "core_cliente"."creado_el",
"core_cliente"."modificado_el", "core_cliente"."nombre",
"core_cliente"."apellido", "core_cliente"."fecha_nacimiento",
"core_cliente"."genero", "core_cliente"."estado_civil",
"core_cliente"."dni", "core_cliente"."domicilio"

Lo que claramente está mal es el group by por todos los campos. En la
base de datos solo hay 3k clientes con 150K movimientos, y está tardando
unos 44759 ms aprox.

Ariel, hice el analize explain y lo pegué en [0].

¿Como le especifico al orm que no haga el group by por todo?

Gracias..

[0] http://explain.depesz.com/s/Eqv

-- 
*Matías E. Varela*
Skype: matu.varela
Jadder: matuu en python.org.ar

------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.python.org.ar/pipermail/pyar/attachments/20141217/dd50573b/attachment.html>


More information about the pyar mailing list