Performance issue in invoice analysis

Bug #1000195 reported by Anders Wallenquist
78
This bug affects 13 people
Affects Status Importance Assigned to Milestone
Odoo Addons (MOVED TO GITHUB)
Fix Released
Medium
OpenERP Publisher's Warranty Team

Bug Description

The sale-module produces a lot of selects to the account_invoice_report database view. I think its one of the widget in the dashboard that does this. Anyway the performance are lousy and a ticking bomb for many 6.1 installations.

This select takes 8000 ms with 450 invoices in the database
SELECT month,price_total FROM "account_invoice_report" WHERE account_invoice_report.id IN (450 ids)

The company creats over 200 000 invoices per year, which was OK with series 5 of OpenERP. It will not be possible now after upgrade to 6.1. There are many installations who creates more than 400 invoices per year, many that creats 400 invoinces per day.

I think we need a temporary table or something instead of this database view. Every time a salesman opens his saleview he hits this problem.

Tags: maintenance

Related branches

Revision history for this message
Lorenzo Battistini (elbati) wrote :

Hello, same problem here.

Maybe this is related to bug 932524 .

Our customer has ~2500 invoices and ~1000 rows in res_currency_rate table.

While opening
accounting -> reporting -> statistics reports -> invoices analysis
on our server, postgresql logs the following durations:

2012-05-18 09:44:14 CEST [1458]: [1-1] user=openerp,db=xxxxx,remote=127.0.0.1(49168) LOG: duration: 12964.719 ms statement: SELECT min(account_invoice_report.id) AS id, count(account_invoice_report.id) AS categ_id_count,"account_invoice_report".categ_id, sum("account_invoice_report"."nbr") AS nbr, sum("account_invoice_report"."product_qty") AS product_qty, sum("account_invoice_report"."price_total") AS price_total FROM "account_invoice_report" WHERE ((((account_invoice_report."date" <= '2012-05-18') AND (account_invoice_report."date" >= '2012-01-01')) AND ((account_invoice_report."state" not in ('draft','cancel')) OR account_invoice_report."state" IS NULL)) AND ((account_invoice_report."type" = 'out_invoice') OR (account_invoice_report."type" = 'out_refund'))) GROUP BY "account_invoice_report".categ_id

2012-05-18 09:51:23 CEST [1458]: [2-1] user=openerp,db=xxxxx,remote=127.0.0.1(49168) LOG: duration: 429323.694 ms statement: SELECT "account_invoice_report".id FROM "account_invoice_report" LEFT JOIN "product_category" ON ("account_invoice_report"."categ_id" = "product_category"."id") WHERE (account_invoice_report."id" in (4219)) ORDER BY "product_category"."parent_left"

2012-05-18 09:58:42 CEST [1458]: [3-1] user=openerp,db=xxxxx,remote=127.0.0.1(49168) LOG: duration: 438652.536 ms statement: SELECT account_invoice_report."categ_id",account_invoice_report.id FROM "account_invoice_report" WHERE account_invoice_report.id IN (4219) ORDER BY date desc

Changed in openobject-addons:
assignee: nobody → OpenERP Publisher's Warranty Team (openerp-opw)
tags: added: maintenance
Revision history for this message
Numérigraphe (numerigraphe) wrote :

The comments on bug #932524 certainly have a point: the currency rate feature is really dubious.
But even when I remove it, the query tiles out on our database (66000 invoice lines, 1200 products, 3 partners).
So there is probably more optimization work to do.
Lionel.

summary: - Performance issue in sale 6.1
+ Performance issue in invoice analysis
Changed in openobject-addons:
status: New → Confirmed
Revision history for this message
Numérigraphe (numerigraphe) wrote :

Dear OpenERP Publisher's Warranty Team, I marked bug #932524 a duplicate of this.
It was assigned to OpenERP R&D Addons Team 3. Can you please check who this bug should be assigned to?
Lionel.

Revision history for this message
Kellogs (jm-poure) wrote :
Download full text (14.5 KiB)

This is a real design bug.

To analyse any query, please run:
EXPLAIN ANALYSE yourSQL query

i.e.
EXPLAIN ANALYSE
SELECT min(account_invoice_report.id) AS id, count(account_invoice_report.id) AS categ_id_count,"account_invoice_report".categ_id, sum("account_invoice_report"."nbr") AS nbr, sum("account_invoice_report"."product_qty") AS product_qty, sum("account_invoice_report"."price_total") AS price_total FROM "account_invoice_report" WHERE ((((account_invoice_report."date" <= '2012-05-18') AND (account_invoice_report."date" >= '2012-01-01')) AND ((account_invoice_report."state" not in ('draft','cancel')) OR account_invoice_report."state" IS NULL)) AND ((account_invoice_report."type" = 'out_invoice') OR (account_invoice_report."type" = 'out_refund'))) GROUP BY "account_invoice_report".categ_id

On my server, even with on 3000 clients ...
the query returns a result in 20 seconds.

"HashAggregate (cost=267661920.65..267661925.15 rows=200 width=32) (actual time=20619.984..20619.986 rows=2 loops=1)"
" -> GroupAggregate (cost=2363456.42..267585641.15 rows=3051180 width=184) (actual time=20459.610..20617.810 rows=1257 loops=1)"
" -> Sort (cost=2363456.42..2371084.37 rows=3051180 width=184) (actual time=20459.384..20459.784 rows=1265 loops=1)"
" Sort Key: ail.product_id, ai.date_invoice, ai.id, cr.rate, (to_char((ai.date_invoice)::timestamp with time zone, 'YYYY'::text)), (to_char((ai.date_invoice)::timestamp with time zone, 'MM'::text)), (to_char((ai.date_invoice)::timestamp with time zone, 'YYYY-MM-DD'::text)), ai.partner_id, ai.payment_term, ai.period_id, u.name, ai.currency_id, ai.journal_id, ai.fiscal_position, ai.user_id, ai.company_id, ai.type, ai.state, pt.categ_id, ai.date_due, ai.address_contact_id, ai.address_invoice_id, ai.account_id, ai.partner_bank_id, ai.residual, ai.amount_total, u.uom_type, u.category_id"
" Sort Method: quicksort Memory: 701kB"
" -> Merge Join (cost=0.00..1492526.05 rows=3051180 width=184) (actual time=11.478..20452.364 rows=1265 loops=1)"
" Merge Cond: (ail.invoice_id = ai.id)"
" -> Nested Loop Left Join (cost=0.00..1475.72 rows=3084 width=86) (actual time=0.067..25.090 rows=2646 loops=1)"
" Join Filter: (u.id = ail.uos_id)"
" -> Nested Loop Left Join (cost=0.00..1058.26 rows=3084 width=68) (actual time=0.047..15.025 rows=2646 loops=1)"
" -> Index Scan using account_invoice_line_invoice_id_index on account_invoice_line ail (cost=0.00..170.50 rows=3084 width=64) (actual time=0.034..3.749 rows=2646 loops=1)"
" -> Index Scan using product_template_pkey on product_template pt (cost=0.00..0.28 rows=1 width=8) (actual time=0.002..0.003 rows=1 loops=2646)"
" Index Cond: (pt.id = ail.product_id)"
" -> Materialize (cost=0.00..1.14 rows=9 width=26) (actual time=0.000..0.001 rows=9 loops=2646)"
" -> Seq Scan on product_uom u (cost=0.00..1.09 rows=9 width=26) (actual time=0.004..0.010 rows=9 loops=1)"
" ...

Revision history for this message
Kellogs (jm-poure) wrote :
Download full text (9.0 KiB)

EXPLAIN ANALYSE
SELECT *
FROM account_invoice_report
LIMIT 1

returns a result in ... 110 seconds.

If this is a usual design problem in OpenERP, I would suggest that you invest in SSD disc and boost PostgreSQL memory.
When a database has a bad designe, it is always necessary to run SSD disc to make sequential scans much faster.

The result of the EXPLAIN ANALYSE:

"Limit (cost=16545936.29..16546023.23 rows=1 width=554) (actual time=110458.111..110458.111 rows=1 loops=1)"
" -> Subquery Scan on account_invoice_report (cost=16545936.29..1202110162.52 rows=13637448 width=554) (actual time=110458.109..110458.109 rows=1 loops=1)"
" -> GroupAggregate (cost=16545936.29..1201973788.04 rows=13637448 width=184) (actual time=110458.107..110458.107 rows=1 loops=1)"
" -> Sort (cost=16545936.29..16580029.91 rows=13637448 width=184) (actual time=110457.872..110457.873 rows=2 loops=1)"
" Sort Key: ail.product_id, ai.date_invoice, ai.id, cr.rate, (to_char((ai.date_invoice)::timestamp with time zone, 'YYYY'::text)), (to_char((ai.date_invoice)::timestamp with time zone, 'MM'::text)), (to_char((ai.date_invoice)::timestamp with time zone, 'YYYY-MM-DD'::text)), ai.partner_id, ai.payment_term, ai.period_id, u.name, ai.currency_id, ai.journal_id, ai.fiscal_position, ai.user_id, ai.company_id, ai.type, ai.state, pt.categ_id, ai.date_due, ai.address_contact_id, ai.address_invoice_id, ai.account_id, ai.partner_bank_id, ai.residual, ai.amount_total, u.uom_type, u.category_id"
" Sort Method: quicksort Memory: 1660kB"
" -> Nested Loop (cost=0.00..12505977.72 rows=13637448 width=184) (actual time=285.840..110434.834 rows=3032 loops=1)"
" Join Filter: (SubPlan 6)"
" -> Nested Loop Left Join (cost=0.00..1642.35 rows=3084 width=174) (actual time=0.093..71.748 rows=3085 loops=1)"
" -> Nested Loop Left Join (cost=0.00..754.58 rows=3084 width=170) (actual time=0.081..39.953 rows=3085 loops=1)"
" Join Filter: (u.id = ail.uos_id)"
" -> Merge Right Join (cost=0.00..337.13 rows=3084 width=152) (actual time=0.063..27.645 rows=3085 loops=1)"
" Merge Cond: (ai.id = ail.invoice_id)"
" -> Index Scan using account_invoice_pkey on account_invoice ai (cost=0.00..125.44 rows=1576 width=92) (actual time=0.021..2.644 rows=1578 loops=1)"
" -> Index Scan using account_invoice_line_invoice_id_index on account_invoice_line ail (cost=0.00..170.50 rows=3084 width=64) (actual time=0.024..9.737 rows=3085 loops=1)"
" -> Materialize (cost=0.00..1.14 rows=9 width=26) (actual time=0.000..0.001 rows=9 loops=3085)"
" -> Seq Scan on product_uom u (cost=0.00..1.09 rows=9 width=26) (actual time=0.004..0.008 rows=9 loops=1)"
" -> Index Scan using product_template_pkey on product_template pt (cost=0.00..0.28 rows=1 width...

Read more...

Revision history for this message
Kellogs (jm-poure) wrote :

I am buying an SSD :)
There is no simple way to around ...

Revision history for this message
Numérigraphe (numerigraphe) wrote : Re: [Bug 1000195] Re: Performance issue in invoice analysis

Le 09/07/2012 17:26, Kellogs a écrit :
> I am buying an SSD :)
> There is no simple way to around ...
>
To bad, I'm already using and SSD :)
I hope someone has the time (and courage :) ) to tackle this.
Lionel.

Revision history for this message
Normunds (Alistek) (3pm) wrote :

We checked overall performance with SSD and ordinary disk along with not fast processor- no noticable difference.

Revision history for this message
Ronald Portier (Therp) (rportier1962) wrote :

No amount of hardware is going to solve problems with bad design.

These kind of queries should simply not be run on opening an application, like going to the sales module. Or should not be run at all, if hte information is needed, rewrite and redesign to get acceptabel performance, instead of hoping that throwing hardware at a problem will make it go away.

In the meantime people might be helped by the following branch, created by Akretion, that among other things allows to disable the sale dashboard:

https://code.launchpad.net/~akretion-team/+junk/addons-no-fluff

Revision history for this message
Francisco Peiro (francisco-peiro) wrote :

Hello,

I have read your bug report,

After analyzing the issue, I've been able to create the table account_invoice_report reducing computational time from 3 min to 10 secs. I attach the patch.

Thanks and waiting for your comments!

Francisco Peiró
Factor Libre

Changed in openobject-addons:
status: Confirmed → Fix Released
Revision history for this message
Martin Trigaux (OpenERP) (mat-openerp) wrote :

Hello,

As you have noticed, the delay is due to the computation of the fields delay_to_pay and due_delay. We have improved the computation to a faster version of the query.

revno: 7254
revision-id: <email address hidden>

Please note that this is not a full fix, it will improve the delay but it's still slow on big databases. If these two fields are not mandatory to you, removing the computation (patch attached, will always return 0) will have way better results.

On a test database, a simple query on account_invoice_report, went from impossible to compute (stopped the computation after some time) to 24sec with the merged patch at revision 7254. Without these two fields (attached patch), it takes 3sec.

Also please note that these fields have been removed in 7.0 (too slow and had an ambiguous meaning)

Changed in openobject-addons:
importance: Undecided → Medium
milestone: none → 6.1
Revision history for this message
Yann Papouin (yann-papouin) wrote :
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.