I'm having a little problem at work, the ORM is generating a very strange query and I need to optimize its result a little. I wrote a more readable version of the query and the result is similar, but the execution time is still the same.
Original Query
Explain Verbose
This is the current formatted query, it returns the correct value but takes about 13 seconds to execute.
select count(*)
from reservation as r
JOIN companyclient as cc ON r.companyclientid = cc.companyclientid
JOIN reservationitem as ri ON r.reservationid = ri.reservationid
LEFT JOIN billingaccount as bi
ON (r.reservationid = bi.reservationid AND cc.companyclientid = bi.companyclientid AND
bi.propertyid = '84'
AND NOT bi.isdeleted
AND bi.groupkey = bi.billingaccountid
AND bi.billingaccounttypeid = '3'
AND bi.reservationid IS NOT NULL
AND bi.statusid = '1')
WHERE r.propertyid = '84'
AND NOT r.isdeleted
AND r.companyclientid is not null
AND ri.tenantid = '025aa64f-67fb-4c23-b975-2b0fc3f5d65a'
AND NOT ri.isdeleted
AND ri.reservationitemstatusid NOT IN (6, 3, 7, 8);
This is the version I wrote in an attempt to optimize (from 13 seconds to 5), avoiding the conditions inside the left join, but the result is different from the original query. The first query returns 29490 and the second query returns 29397.
select count(*)
from reservation as r
JOIN companyclient as cc ON r.companyclientid = cc.companyclientid
JOIN reservationitem as ri ON r.reservationid = ri.reservationid
LEFT JOIN billingaccount as bi
ON (r.reservationid = bi.reservationid AND cc.companyclientid = bi.companyclientid)
WHERE r.propertyid = '84'
AND NOT r.isdeleted
AND r.companyclientid is not null
AND ri.tenantid = '025aa64f-67fb-4c23-b975-2b0fc3f5d65a'
AND NOT ri.isdeleted
AND ri.reservationitemstatusid NOT IN (6, 3, 7, 8)
AND (bi is null or bi.propertyid = '84'
AND NOT bi.isdeleted
AND bi.groupkey = bi.billingaccountid
AND bi.billingaccounttypeid = '3'
AND bi.reservationid IS NOT NULL
AND bi.statusid = '1')
My question is, how can I optimize the first query, I've tried some methods but I haven't had much success. I understand that the count is linear and its time is based on the size of the query return, but I imagine it's too slow for a 30K rows query.
In this specific case, I need the total of items to calculate the number of pages in the limit offset pagination.
Thanks in advance to everyone who had the patience to read, I accept any help.
Size of tables used in the example:
- reservation: 288549 rows
- companyclient: 50614 rows
- reservationitem: 387820 rows
- billingaccount: 772521 rows
CREATE TABLE
statements for all 3 tables, including indexes - or the output of\d reservation
from psql (again for all 3 tables).