N+1 artinya: satu query ambil daftar, lalu satu query tambahan untuk tiap baris. Dengan 2.000 record, jadi 2.001 kali bolak-balik ke database.
Versi lambat
for order in self.env['sale.order'].search([('state', '=', 'sale')]):
total += len(self.env['sale.order.line'].search([('order_id', '=', order.id)]))
Tiap putaran loop menyentuh database lagi.
Perbaikan
Tanya sekali, kelompokkan di 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)
Untuk akses field biasa, ORM sudah prefetch per 1.000 record selama kamu iterasi recordset yang sama. Jangan bikin recordset baru di dalam loop pakai browse(order.id), itu merusak prefetch.
Cara mengenalinya
Jalankan Odoo dengan --log-level=debug_sql lalu buka layarnya. Bentuk query yang sama berulang banyak kali itu tandanya.
Pegangan
Kalau ada query di dalam for, tanya: bisa nggak satu read_group, mapped, atau search sebelum loop mengerjakannya?