October 12th, 2026

The N+1 query problem in Odoo, with a fix

N+1 means: one query to get the list, then one extra query per row. With 2,000 records, that is 2,001 round trips.

The slow version

for order in self.env['sale.order'].search([('state', '=', 'sale')]):
    total += len(self.env['sale.order.line'].search([('order_id', '=', order.id)]))

Every pass of the loop hits the database again.

The fix

Ask once, group in the database:

data = self.env['sale.order.line'].read_group(
    [('order_id.state', '=', 'sale')],
    ['order_id'], ['order_id'],
)
total = sum(r['order_id_count'] for r in data)

For plain field access, the ORM prefetches in batches of 1,000 as long as you iterate over the same recordset. Do not rebuild a new recordset inside the loop with browse(order.id), because that breaks prefetching.

How to spot it

Start Odoo with --log-level=debug_sql and run the screen. Seeing the same query shape repeat many times is the sign.

Rule of thumb

If a query sits inside a for, ask: can one read_group, mapped or search before the loop do this?

← All posts