Very poor performance on window Generate Invoice (manual) with RMA

Description

If there is a large number of Customer RMA in the system (in our case +500), the performance in Form 'Generate Invoices (manual)' with Document Type=RMA - upon retrieving customer RMA documents for the creation of credit memos - becomes unacceptable. Also database activity spikes for an extended period of time slowing down the entire system.

The root cause is the SQL statement under getRMASql() in org.adempiere.ui/src/org/compiere/apps/form/InvoiceGen.java.
We were able to optimize the performance of this SQL statement as per attachment.
Please consider pushing the SQL statement change to the trunk.

Environment

None

Attachments

1

Activity

Show:

Michael Powacht August 5, 2021 at 12:25 PM

Thanks for your info .

Carlos Ruiz August 5, 2021 at 10:24 AM

Hi

Thanks for your information, I got curious why that worked without the index and did some tests.

Firstly filled the table M_RMALine with 200.000 records and checked the execution of both queries:

The old query shows an execution plan with this cost:
Sort (cost=20109.92..20109.93 rows=1 width=546)

The new query shows this cost:
Sort (cost=94.74..94.74 rows=1 width=546)

I tried created an index on M_RMALine.M_RMA_ID but postgres didn't make any use of this new index, so I was wrongly assuming that would help.

Just to be on the safe side I conducted the same test in oracle, and oracle makes the same execution plan for both cases - and answer a lot faster than postgresql.

Regards,

Carlos Ruiz

Michael Powacht August 4, 2021 at 2:28 AM

Thank you Carlos!
I hope you and your family are safe and healthy!

I'm currently running on PG 12.5, but the SQL statement change in InvoiceGen.java was made when still running on PG 10.x with similar performance gains.

I just simulated a full table scan with both query versions, comparing the performance of IN vs. EXISTS using 12.5/PGAdmin and the difference is huge. Here is the query:

IN Statement:

Successfully run. Total query runtime: 12 min 58 secs. 16 rows affected.

EXISTS Statement:

Successfully run. Total query runtime: 1 secs 166 msec. 16 rows affected.

 

I agree, we should defintiley index foreign keys in line-tables to speed up the performance of parent-child relationships.

To make sure. I've checked all indexes currently in my database for all the tables accessed in the above query using:

 

tablename

indexname

indexdef

c_bpartner

c_bpartner_bporg

CREATE INDEX c_bpartner_bporg ON adempiere.c_bpartner USING btree (ad_orgbp_id)

c_bpartner

c_bpartner_name

CREATE INDEX c_bpartner_name ON adempiere.c_bpartner USING btree (name)

c_bpartner

c_bpartner_uu_idx

CREATE UNIQUE INDEX c_bpartner_uu_idx ON adempiere.c_bpartner USING btree (c_bpartner_uu)

c_bpartner

c_bpartner_pkey

CREATE UNIQUE INDEX c_bpartner_pkey ON adempiere.c_bpartner USING btree (c_bpartner_id)

c_bpartner

c_bpartner_value

CREATE UNIQUE INDEX c_bpartner_value ON adempiere.c_bpartner USING btree (ad_client_id, value)

c_bpartner

zi_c_bpartner_taxid

CREATE UNIQUE INDEX zi_c_bpartner_taxid ON adempiere.c_bpartner USING btree (ad_org_id, iscustomer, c_bp_group_id, taxid)

c_doctype

c_doctype_pkey

CREATE UNIQUE INDEX c_doctype_pkey ON adempiere.c_doctype USING btree (c_doctype_id)

c_doctype

c_doctype_name

CREATE UNIQUE INDEX c_doctype_name ON adempiere.c_doctype USING btree (ad_client_id, name)

c_doctype

c_doctype_uu_idx

CREATE UNIQUE INDEX c_doctype_uu_idx ON adempiere.c_doctype USING btree (c_doctype_uu)

m_inout

m_inout_pkey

CREATE UNIQUE INDEX m_inout_pkey ON adempiere.m_inout USING btree (m_inout_id)

m_inout

m_inout_bpartner

CREATE INDEX m_inout_bpartner ON adempiere.m_inout USING btree (c_bpartner_id)

m_inout

m_inout_documentno

CREATE INDEX m_inout_documentno ON adempiere.m_inout USING btree (documentno)

m_inout

m_inout_order

CREATE INDEX m_inout_order ON adempiere.m_inout USING btree (c_order_id)

m_inout

m_inout_uu_idx

CREATE UNIQUE INDEX m_inout_uu_idx ON adempiere.m_inout USING btree (m_inout_uu)

m_inout

idxm_inout_proc_on

CREATE INDEX idxm_inout_proc_on ON adempiere.m_inout USING btree (posted, processed, processedon, ad_client_id)

m_inoutline

m_inoutline_uu_idx

CREATE UNIQUE INDEX m_inoutline_uu_idx ON adempiere.m_inoutline USING btree (m_inoutline_uu)

m_inoutline

m_inoutline_pkey

CREATE UNIQUE INDEX m_inoutline_pkey ON adempiere.m_inoutline USING btree (m_inoutline_id)

m_inoutline

m_inoutline_inout

CREATE INDEX m_inoutline_inout ON adempiere.m_inoutline USING btree (m_inout_id)

m_inoutline

m_inoutline_product

CREATE INDEX m_inoutline_product ON adempiere.m_inoutline USING btree (m_product_id)

m_inoutline

m_inoutline_rmaline_id

CREATE INDEX m_inoutline_rmaline_id ON adempiere.m_inoutline USING btree (m_rmaline_id)

m_rma

m_rma_pkey

CREATE UNIQUE INDEX m_rma_pkey ON adempiere.m_rma USING btree (m_rma_id)

m_rma

m_rma_uu_idx

CREATE UNIQUE INDEX m_rma_uu_idx ON adempiere.m_rma USING btree (m_rma_uu)

m_rmaline

m_rmaline_pkey

CREATE UNIQUE INDEX m_rmaline_pkey ON adempiere.m_rmaline USING btree (m_rmaline_id)

m_rmaline

m_rmaline_uu_idx

CREATE UNIQUE INDEX m_rmaline_uu_idx ON adempiere.m_rmaline USING btree (m_rmaline_uu)

There are a few custom indexes we created, but it seems none of them affecting above query or the exists-statement.
Index m_inoutline_rmaline_id I only created a few days ago to improve performance for another report and also doesn't affect above query.

Thanks also for your advice regarding the feature branch, that's very helpful.

Cheers,
Michael

Carlos Ruiz August 3, 2021 at 2:13 PM

Hi - thanks for the pull request 809

 

in the pull request wrote:

please provide the PostgreSQL version you have tested this and the corresponding query analysis that shows the new version of the SQL is more efficient.

 

I also took a look, first generic thing: is better to do the commit in a branch feature - as you did it in master it will become complex for you to manage keeping the pull request up to date when the master start changing

 

Now, about the change, it is changing this statement:

with this:

now - analyzing the new EXISTS clause it is basically the same as the IN clause - but I think it’s not really relevant to improve the performance of the query. What is really needed there is an index on M_RMALine at least for the column M_RMA_ID. I think probably you created this index on your database, and the patch would be incomplete and probably EXISTS performance can be worst without such index.

 

So, I think instead of this proposed change, the only thing needed is probably the index, and by the way, there must be a lot of “line” tables where an index to resolve the foreign key on the parent document is worthy, maybe we can do something generic to add those indexes to the most common tables: C_OrderLine, C_InvoiceLine, M_*Line, etc

 

Can you please check your DB, I think you must have an index created to make the change work.

 

Regards,

Carlos Ruiz

Michael Powacht July 31, 2021 at 3:54 AM

Thanks Carlos, I submitted a pull request to idempiere/master.

Fixed

Details

Assignee

Reporter

Labels

Components

Fix versions

Affects versions

Priority

Created July 25, 2020 at 3:19 AM
Updated October 1, 2021 at 2:46 PM
Resolved August 5, 2021 at 10:24 AM