Utilizando SQL para obtener estadísticas dentro de nuestros modelos

12 de setiembre de 2025 por
Gustavo Orrillo
| Sin comentarios aún
 

Usar el ORM para acceder a la información dentro de Odoo es una buena práctica. Y para de contar. Muchas veces cuando las papas queman en términos de performance, nos vemos obligados a acceder directamente a la base de datos para obtener los datos mediante SQL. Lo cual no es mala idea ya que nos permite obtener ganancias de performance de por lo menos dos a diez veces más rápido.

A que se debe esto? Cada vez que realizamos una llamada del ORM, Odoo termina haciendo esto:

  • Crear los objetos del recorset
  • Chequea seguridad, recomputa campos leidos
  • Actualiza el cache
  • Convierte las filas leídas en objetos de Python

Lo cual esta bien si estamos trabajando con decenas de registros, pero si estamos trabajando con centenares o miles de registros (como sucede con clientes o productos) estamos en problemas.

Para ello conviene acceder a los datos directamente mediante SQL. Una forma facil es hacerlo con campos computados, por ejemplo como hacemos a continuación:

cs_avg_qty_orders = fields.Integer('cantidad de pedidos por mes',compute='_compute_cs_avg_qty_orders')
cs_stddev_qty_orders = fields.Integer('Desvio standard de pedidos por mes',compute='_compute_cs_stddev_qty_orders')
cs_qty_orders = fields.Integer('cantidad de pedidos (kgs)',compute='_compute_cs_qty_unit_orders')


En donde para cada uno de los campos (cantidad, promedio y desvio standard) definimos un campo computado con su correspondiente método. Y los métodos son los siguientes


def _compute_cs_qty_orders(self):
for rec in self:
self.env.cr.execute("""
SELECT count(*)
FROM sale_order
WHERE partner_id = %s AND credit_scoring = TRUE
AND date_order >= (CURRENT_DATE - INTERVAL '4 months')
""", [rec.id])
rec.cs_qty_orders = self.env.cr.fetchone()[0] or 0

def _compute_cs_avg_qty_orders(self):
for rec in self:
self.env.cr.execute("""
SELECT AVG(order_count)
FROM (
SELECT DATE_TRUNC('month', date_order) AS month, COUNT(*) AS order_count
FROM sale_order
WHERE date_order IS NOT NULL
AND partner_id = %s AND credit_scoring = TRUE
AND date_order >= (CURRENT_DATE - INTERVAL '4 months')
GROUP BY DATE_TRUNC('month', date_order)
) sub;
""", [rec.id])
rec.cs_avg_qty_orders = self.env.cr.fetchone()[0] or 0

def _compute_cs_stddev_qty_orders(self):
for rec in self:
self.env.cr.execute("""
SELECT STDDEV_POP(order_count)
FROM (
SELECT DATE_TRUNC('month', date_order) AS month, COUNT(*) AS order_count
FROM sale_order
WHERE date_order IS NOT NULL
AND partner_id = %s AND credit_scoring = TRUE
AND date_order >= (CURRENT_DATE - INTERVAL '4 months')
GROUP BY DATE_TRUNC('month', date_order)
) sub;
""", [rec.id])
rec.cs_stddev_qty_orders = self.env.cr.fetchone()[0] or 0

Como podran ver, Odoo permite ejecutar dentro de un método una consulta de SQL (ya sea para consultar o actualizar datos). Solo hace falta saber definir el SQL (no es tan dificil aprenderlo), y al resultado de la consulta, asignarlo al campo computado. No es el fin del mundo.

Por último; tengan en cuenta que si bien el ORM de Odoo esta optimizado para performance; PostgreSQL es muchísimo más rápido. Como pueden ver en los ejemplos que acabamos de mostrar, en PostgreSQL estan ejecutandose sumarizaciones y funciones estadísticas como promedios y desvíos estandard.

Gustavo Orrillo 12 de setiembre de 2025
Compartir
Archivar
Identificarse dejar un comentario