We have a complex query which is dynamically built depending on different options on the customer and runs a query for data. We have functions in Azure which are running these queries to build reporting data every night, we run approx. 30k of these. The queries in isolation are about as fast as I can get them, approximately 100ms but when we are running functions in parallel on the consumption plan in Azure (restricted to a maximum of 5 functions running at the same time) the performance of the queries is dropping off and some are even timing out at 5 minutes, some which are timing out I have tested in isolation and are coming in at under 100ms. There are no writes as this is using a read replica in Azure to load this data.
We are running in Postgres 11.6 on hosted Azure with PgBouncer on a VM. All these queries are going to a read replica which is configured to a 4 vCore Memory Optimized.
What changes can we make to allow more parallel execution of these queries or is scaling up our only option?
I would like to share the EXPLAIN ANALYZE but this is restricted by the business. Please let me know what information would help and I will try to provide as much as possible.
CTE Scan on bravo_zulu romeo (cost=2151.89..2151.94 rows=1 width=204) (actual time=27.756..84.147 rows=36 loops=1)
CTE bravo_zulu
-> Nested Loop (cost=13.84..2151.89 rows=1 width=139) (actual time=27.744..84.009 rows=36 loops=1)
-> Nested Loop (cost=13.42..2151.43 rows=1 width=139) (actual time=26.811..76.983 rows=36 loops=1)
-> Nested Loop (cost=12.86..130.51 rows=1 width=44) (actual time=7.471..19.361 rows=29 loops=1)
-> Nested Loop (cost=4.88..97.73 rows=1 width=24) (actual time=7.410..10.480 rows=24 loops=1)
-> Index Scan using yankee on xray_zulu foxtrot_uniform (cost=0.28..8.29 rows=1 width=8) (actual time=1.339..1.340 rows=1 loops=1)
Index Cond: ("juliet" = 20)
-> Bitmap Heap Scan on golf_delta hotel_six (cost=4.60..89.43 rows=1 width=20) (actual time=6.064..9.123 rows=24 loops=1)
Recheck Cond: ("delta_oscar_hotel" = foxtrot_uniform."lima")
Filter: ("juliet" = ANY ('foxtrot_oscar'::integer[]))
Rows Removed by Filter: 442
Heap Blocks: exact=65
-> Bitmap Index Scan on papa (cost=0.00..4.60 rows=42 width=0) (actual time=0.024..0.024 rows=466 loops=1)
Index Cond: ("delta_oscar_hotel" = foxtrot_uniform."lima")
-> Bitmap Heap Scan on delta_sierra_two bravo_hotel (cost=7.98..32.76 rows=2 width=20) (actual time=0.321..0.363 rows=1 loops=24)
Recheck Cond: ((hotel_six."juliet" = "xray_india") OR (hotel_six."juliet" = "foxtrot_foxtrot"))
Filter: ("hotel_golf" = 23)
Rows Removed by Filter: 10
Heap Blocks: exact=240
-> BitmapOr (cost=7.98..7.98 rows=9 width=0) (actual time=0.066..0.066 rows=0 loops=24)
-> Bitmap Index Scan on delta_sierra_sierra (cost=0.00..3.99 rows=5 width=0) (actual time=0.063..0.063 rows=11 loops=24)
Index Cond: (hotel_six."juliet" = "xray_india")
-> Bitmap Index Scan on xray_sierra (cost=0.00..3.99 rows=4 width=0) (actual time=0.002..0.002 rows=0 loops=24)
Index Cond: (hotel_six."juliet" = "foxtrot_foxtrot")
-> Index Only Scan using echo on xray_papa victor (cost=0.56..2020.44 rows=48 width=102) (actual time=1.606..1.986 rows=1 loops=29)
Index Cond: (("five_lima" = 23) AND ("seven_yankee" = bravo_hotel."november") AND ("charlie_hotel" five_romeo NULL))
Filter: (("three" = 'charlie_romeo'::text) AND (("alpha" = 'golf_bravo'::text) OR ("alpha" = 'delta_echo'::text)) AND ((("alpha" = ANY ('mike_juliet'::text[])) AND ("mike_lima" >= 'xray_whiskey'::date) AND ("mike_lima" <= 'uniform'::date)) OR (("alpha" = ANY ('kilo'::text[])) AND ("quebec_uniform" >= 'xray_whiskey'::date) AND ("quebec_uniform" <= 'uniform'::date)) OR (("alpha" = 'quebec_alpha_quebec'::text) AND ("quebec_uniform" >= 'xray_whiskey'::date) AND ("quebec_uniform" <= 'uniform'::date) AND ("mike_lima" >= 'xray_whiskey'::date) AND ("mike_lima" <= 'uniform'::date))) AND ((("alpha" = ANY ('oscar'::text[])) AND ("seven_india" = ANY ('four'::text[]))) OR (("alpha" = ANY ('quebec_alpha_delta'::text[])) AND ("seven_charlie" = ANY ('four'::text[])))))
Rows Removed by Filter: 1059
Heap Fetches: 0
-> Index Scan using bravo_papa on tango sierra (cost=0.42..0.45 rows=1 width=16) (actual time=0.194..0.194 rows=1 loops=36)
Index Cond: (("bravo_two" = 23) AND ("delta_tango" = six1."delta_oscar_romeo"))
SubPlan
-> Result (cost=0.01..0.02 rows=1 width=32) (actual time=0.001..0.001 rows=1 loops=36)
One-Time Filter: ((romeo.zulu = 'golf_bravo'::text) AND (romeo.golf_uniform = 20) AND (romeo.charlie_two = 'charlie_romeo'::text))
SubPlan
-> Result (cost=0.01..0.02 rows=1 width=32) (actual time=0.000..0.000 rows=0 loops=36)
One-Time Filter: ((romeo.zulu = 'delta_echo'::text) AND (romeo.charlie_two = 'charlie_romeo'::text) AND (romeo.golf_uniform = 20))
Planning time: 19.385 ms
Execution time: 84.373 ms
Above is an anonymised execution plan, this same query when running the functions in Azure in parallel timed out.
Table sizes are not large, largest is 8m rows but all others are low 100k.
When analysing a problem like this I find it usefull to restate what we know:
Your queries go from taking 100ms to timing out after 5 minutes.
This is happening on a 4 core system that is restricted to a maximum of 5 functions running at the same time.
This sounds more like a deadlock problem than a load problem.
There are 2 things that you could try:
Change to run one report at a time, to see if the timeouts disappear
Check your SQL code for and "with update" that could be leading to database locks
Edit:
Baced on answer in comment we can assume that it is not a database lock problem
Next thing to check is the connection to the database. It could be that the system is running out of available connections to the database. Things to check:
Max number of connections available
Is connection pooling used
Are connections being closed /released back to the pool, when they are no longer needed
Related
I am trying to understand a Postgres explain plan using this website (http://explain.depesz.com).
This is my plan:
Unique (cost=795.43..800.89 rows=546 width=23) (actual time=0.599..0.755 rows=620 loops=1)
-> Sort (cost=795.43..796.79 rows=546 width=23) (actual time=0.598..0.626 rows=620 loops=1)
Sort Key: m.member_id, c.total_charged_amt DESC, c.claim_status
Sort Method: quicksort Memory: 73kB
-> Nested Loop (cost=9.64..770.60 rows=546 width=23) (actual time=0.023..0.342 rows=620 loops=1)
-> Bitmap Heap Scan on member m (cost=9.22..222.50 rows=63 width=8) (actual time=0.016..0.024 rows=62 loops=1)
Recheck Cond: (((member_id >= 1584161838) AND (member_id <= 1584161898)) OR (member_birth_dt = '1978-03-13'::date))
Heap Blocks: exact=3
-> BitmapOr (cost=9.22..9.22 rows=63 width=0) (actual time=0.013..0.013 rows=0 loops=1)
-> Bitmap Index Scan on member_pkey (cost=0.00..4.31 rows=2 width=0) (actual time=0.007..0.007 rows=61 loops=1)
Index Cond: ((member_id >= 1584161838) AND (member_id <= 1584161898))
-> Bitmap Index Scan on idx_dob (cost=0.00..4.88 rows=61 width=0) (actual time=0.006..0.006 rows=1 loops=1)
Index Cond: (member_birth_dt = '1978-03-13'::date)
-> Index Scan using idx_memberid on claim c (cost=0.42..8.60 rows=10 width=23) (actual time=0.001..0.003 rows=10 loops=62)
Index Cond: (member_id = m.member_id)
Planning Time: 0.218 ms
Execution Time: 0.812 ms
The plan is also available in the following link: https://explain.depesz.com/s/Qzau.
I have following questions:
Bitmap Index Scans which runs in 0.007s and 0.006s respectively runs in parallel because of indentation.
So why does Bitmapor start at 0.013s? Why is it adding time of both its children? The start time of Bitmapor should be the maximum of its 2 children. So ideally the exclusive time of Bitmapor should be 0.006 (0.013-0.007), but it is 0 (0.013-0.007-0.006)
Bitmap Heap Scan and index scan are children of Nested Loop and run in 0.024s and 0.186s, respectively.
Because of the indentation I assume these 2 children run in parallel. So the parent exclusive time should be 0.156 (0.342-0.186), but instead it is 0.132(0.342-0.186-0.24).
My understanding is we should subtract maximum of the child timings (since they run in parallel) to get the exclusive time spent in the node. But instead it is adding up child timings and then subtracting the sum from the end time of the parent to get the exclusive time. Did i understand incorrectly about explain plans?
Any help is really appreciated as I am totally confused with interpreting them.
As the horse said, there is no parallel processing involved. If parallel query were involved, you would see a Gather node that collects the results.
The indentation visualizes the graph of the query execution plan:
Unique
|
Sort
|
Nested Loop
/ \
Bitmap Heap Scan Index Scan
|
Bitmap Or
/ \
Bitmap Index Scan Bitmap Index Scan
That explains why explain.depesz.com calculates the exclusive time the way it does. Note that that is just a best effort, not the absolute truth, because (for example) a "bitmap or" does not take zero time. But explain.depesz.com can only go by the numbers it gets from EXPLAIN.
Recently we experienced a performance problem in Production Aurora PG cluster. This is an EXPLAIN ANALYZE of the query.
The majority of the time is spent on Bitmap Index Scan on job_stage (cost=0.00..172.93 rows=9666 width=0) (actual time=238.410..238.410 rows=2019444 loops=1) where 2019444 are scanned. However, what troubles me is that there are only 70k rows in this table. Autovacuum is turned on, but the RDS was overloaded recently from another issue. We suspect that the autovacuum was running behind. If that is the case, would it explain our observation the scanned row exceeds actual row in table?
Nested Loop (cost=229.16..265.28 rows=1 width=464) (actual time=239.815..239.815 rows=0 loops=1)
-> Nested Loop (cost=228.62..252.71 rows=1 width=540) (actual time=239.814..239.814 rows=0 loops=1)
Join Filter: (job.scanner_uuid = scanner_resource_pool.resource_uuid)
Rows Removed by Join Filter: 1
-> Index Scan using scanner_resource_pool_scanner_index on scanner_resource_pool (cost=0.41..8.43 rows=1 width=115) (actual time=0.017..0.019 rows=1 loops=1)
Index Cond: ((box_uuid = '5d8a7e0c-23ff-4853-bb6d-ffff6a38afa7'::text) AND (scanner_uuid = '9be9ac50-de05-4ddd-9545-ddddc484dce'::text))
-> Bitmap Heap Scan on job (cost=228.22..244.23 rows=4 width=464) (actual time=239.790..239.791 rows=1 loops=1)
Recheck Cond: ((box_uuid = '5d8a7e0c-23ff-4853-bb6d-ffff6a38afa7'::text) AND (stage = 'active'::text))
Rows Removed by Index Recheck: 6
Heap Blocks: exact=791
-> BitmapAnd (cost=228.22..228.22 rows=4 width=0) (actual time=238.913..238.913 rows=0 loops=1)
-> Bitmap Index Scan on job_box_status (cost=0.00..55.04 rows=1398 width=0) (actual time=0.183..0.183 rows=899 loops=1)
Index Cond: (box_uuid = '5d8a7e0c-23ff-4853-bb6d-ffff6a38afa7'::text)
-> Bitmap Index Scan on job_stage (cost=0.00..172.93 rows=9666 width=0) (actual time=238.410..238.410 rows=2019444 loops=1)
Index Cond: (stage = 'active'::text)
-> Index Only Scan using uc_box_uuid on scanner (cost=0.54..12.56 rows=1 width=87) (never executed)
Index Cond: ((box_uuid = '5d8a7e0c-23ff-4853-bb6d-ffff6a38afa7'::text) AND (uuid = '9be9ac50-de05-4ddd-9545-ddddc484dce'::text))
Heap Fetches: 0
Planning time: 1.274 ms
Execution time: 239.876 ms
I found my answer by confirming with AWS. If autovacuum was running behind, the EXPLAIN ANALYZE result may show this discrepancy.
I have one complexe query generated by Hibernate for JBPM. I can't really modify it and i'm searching to optimize it as much as possible.
I found out that ORDER BY DESC is way slower than ORDER BY ASC, do you have any idea ?
PostgreSQL Version : 9.4
Schema : https://pastebin.com/qNZhrbef
Query :
select
taskinstan0_.ID_ as ID1_27_,
taskinstan0_.VERSION_ as VERSION3_27_,
taskinstan0_.NAME_ as NAME4_27_,
taskinstan0_.DESCRIPTION_ as DESCRIPT5_27_,
taskinstan0_.ACTORID_ as ACTORID6_27_,
taskinstan0_.CREATE_ as CREATE7_27_,
taskinstan0_.START_ as START8_27_,
taskinstan0_.END_ as END9_27_,
taskinstan0_.DUEDATE_ as DUEDATE10_27_,
taskinstan0_.PRIORITY_ as PRIORITY11_27_,
taskinstan0_.ISCANCELLED_ as ISCANCE12_27_,
taskinstan0_.ISSUSPENDED_ as ISSUSPE13_27_,
taskinstan0_.ISOPEN_ as ISOPEN14_27_,
taskinstan0_.ISSIGNALLING_ as ISSIGNA15_27_,
taskinstan0_.ISBLOCKING_ as ISBLOCKING16_27_,
taskinstan0_.LOCKED as LOCKED27_,
taskinstan0_.QUEUE as QUEUE27_,
taskinstan0_.TASK_ as TASK19_27_,
taskinstan0_.TOKEN_ as TOKEN20_27_,
taskinstan0_.PROCINST_ as PROCINST21_27_,
taskinstan0_.SWIMLANINSTANCE_ as SWIMLAN22_27_,
taskinstan0_.TASKMGMTINSTANCE_ as TASKMGM23_27_
from JBPM_TASKINSTANCE taskinstan0_, JBPM_VARIABLEINSTANCE stringinst1_, JBPM_PROCESSINSTANCE processins2_, JBPM_VARIABLEINSTANCE variablein3_
where stringinst1_.CLASS_='S'
and taskinstan0_.PROCINST_=processins2_.ID_
and taskinstan0_.ID_=variablein3_.TASKINSTANCE_
and variablein3_.NAME_ = 'NIR'
and taskinstan0_.QUEUE = 'ERT_TPS'
and (processins2_.ORGAPATH_ like '/ERT%')
and taskinstan0_.ISOPEN_= 't'
and variablein3_.ID_=stringinst1_.ID_
order by stringinst1_.STRINGVALUE_ ASC limit '10';
Explain result for ASC :
Limit (cost=1.71..11652.93 rows=10 width=646) (actual time=6.588..82.407 rows=10 loops=1)
-> Nested Loop (cost=1.71..6215929.27 rows=5335 width=646) (actual time=6.587..82.402 rows=10 loops=1)
-> Nested Loop (cost=1.29..6213170.78 rows=5335 width=646) (actual time=6.578..82.363 rows=10 loops=1)
-> Nested Loop (cost=1.00..6159814.66 rows=153812 width=13) (actual time=0.537..82.130 rows=149 loops=1)
-> Index Scan Backward using totoidx10 on jbpm_variableinstance stringinst1_ (cost=0.56..558481.07 rows=11199905 width=13) (actual time=0.018..11.914 rows=40182 loops=1)
Filter: (class_ = 'S'::bpchar)
-> Index Scan using jbpm_variableinstance_pkey on jbpm_variableinstance variablein3_ (cost=0.43..0.49 rows=1 width=16) (actual time=0.002..0.002 rows=0 loops=40182)
Index Cond: (id_ = stringinst1_.id_)
Filter: ((name_)::text = 'NIR'::text)
Rows Removed by Filter: 1
-> Index Scan using jbpm_taskinstance_pkey on jbpm_taskinstance taskinstan0_ (cost=0.29..0.34 rows=1 width=641) (actual time=0.001..0.001 rows=0 loops=149)
Index Cond: (id_ = variablein3_.taskinstance_)
Filter: (isopen_ AND ((queue)::text = 'ERT_TPS'::text))
Rows Removed by Filter: 0
-> Index Only Scan using idx_procin_2 on jbpm_processinstance processins2_ (cost=0.42..0.51 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=10)
Index Cond: (id_ = taskinstan0_.procinst_)
Filter: ((orgapath_)::text ~~ '/ERT%'::text)
Heap Fetches: 0
Planning time: 2.598 ms
Execution time: 82.513 ms
Explain result for DESC :
Limit (cost=1.71..11652.93 rows=10 width=646) (actual time=8144.871..8144.986 rows=10 loops=1)
-> Nested Loop (cost=1.71..6215929.27 rows=5335 width=646) (actual time=8144.870..8144.984 rows=10 loops=1)
-> Nested Loop (cost=1.29..6213170.78 rows=5335 width=646) (actual time=8144.858..8144.951 rows=10 loops=1)
-> Nested Loop (cost=1.00..6159814.66 rows=153812 width=13) (actual time=8144.838..8144.910 rows=20 loops=1)
-> Index Scan using totoidx10 on jbpm_variableinstance stringinst1_ (cost=0.56..558481.07 rows=11199905 width=13) (actual time=0.066..2351.727 rows=2619671 loops=1)
Filter: (class_ = 'S'::bpchar)
Rows Removed by Filter: 906237
-> Index Scan using jbpm_variableinstance_pkey on jbpm_variableinstance variablein3_ (cost=0.43..0.49 rows=1 width=16) (actual time=0.002..0.002 rows=0 loops=2619671)
Index Cond: (id_ = stringinst1_.id_)
Filter: ((name_)::text = 'NIR'::text)
Rows Removed by Filter: 1
-> Index Scan using jbpm_taskinstance_pkey on jbpm_taskinstance taskinstan0_ (cost=0.29..0.34 rows=1 width=641) (actual time=0.002..0.002 rows=0 loops=20)
Index Cond: (id_ = variablein3_.taskinstance_)
Filter: (isopen_ AND ((queue)::text = 'ERT_TPS'::text))
-> Index Only Scan using idx_procin_2 on jbpm_processinstance processins2_ (cost=0.42..0.51 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=10)
Index Cond: (id_ = taskinstan0_.procinst_)
Filter: ((orgapath_)::text ~~ '/ERT%'::text)
Heap Fetches: 0
Planning time: 2.080 ms
Execution time: 8145.053 ms
Tables infos :
jbpm_variableinstance 12100592 rows
jbpm_taskinstance 69913 rows
jbpm_processinstance 97546 rows
If you have any idea, thanks
This typically only happens when OFFSET and / or LIMIT are involved (as is the case here).
The key difference is this line in the EXPLAIN output for the query with DESC:
Rows Removed by Filter: 906237
Meaning that while the first 10 rows in the index totoidx10 match when scanning backwards (which matches your ASC ordering, obviously), Postgres has to filter ~ 900k rows before it finally finds qualifying rows when scanning the same index forward.
A matching multicolumn index (with the right sort order) might help a lot.
Or, since Postgres chooses an unfavorable query plan, maybe just updated (or more detailed) table statistics or cost settings.
Related:
Keep PostgreSQL from sometimes choosing a bad query plan
Optimizing queries on a range of timestamps (two columns)
I have having a problem where the same query on a table sometimes takes several seconds and most times completes in a few milliseconds. Restart of Postgres seems to resolve the issue and keep it away for a couple of days.
Table - alarm
20 clients reading from the table.
1 client making several inserts and udpates every second. Delete/purge is a nightly cron.
Plenty of RAM still available, only 20% of CPU on the host being used.
After the above conditions persist for a while, the query starts taking 5+ seconds to complete.
Just restart of the clients and Postgres solves this by bring it down to few milliseconds.
explain analyze shows a sequential scan on this table both the times. But it is in the order of milliseconds when Postgres is just started and later it increases to a few seconds.
There are about 25000 records in this table.
Any suggestions, ideas on how to debug when the seq scan is slow? Could it be fragmentation in the shared_buffer or locking of the table causing this. I doubt it is a disk or IO issue because they should cause a problem irrespective of when Postgres is started.
At the time of the issue, I missed using buffers in analyze. The output is like below:
explain analyze SELECT s.severity, s.severityid from SEVERITY s where s.severityid =(select MIN(severityid) from ALARM a, (SELECT * FROM RESOURCEDETAILS) as RESOURCEDETAILS WHERE RESOURCEDETAILS.resourcegroupid = 132 AND RESOURCEDETAILS.resourceid = a.resourceid AND a.severityid 1 AND a.severityid 2 AND a.severityid 7);
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on severity s (cost=4701.39..4702.47 rows=1 width=13) (actual time=7057.939..7057.940 rows=1 loops=1)
Filter: (severityid = $0)
Rows Removed by Filter: 6
InitPlan 1 (returns $0)
-> Aggregate (cost=4701.38..4701.39 rows=1 width=8) (actual time=7057.918..7057.918 rows=1 loops=1)
-> Hash Join (cost=533.69..4701.25 rows=51 width=8) (actual time=1849.630..7057.783 rows=223 loops=1)
Hash Cond: (a.resourceid = resourcedetails.resourceid)
-> Seq Scan on alarm a (cost=0.00..4157.70 rows=2491 width=16) (actual time=45.792..6608.120 rows=852 loops=1)
Filter: ((severityid 1) AND (severityid 2) AND (severityid 7))
Rows Removed by Filter: 24376
-> Hash (cost=528.27..528.27 rows=434 width=8) (actual time=448.540..448.540 rows=19 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 1kB
-> Bitmap Heap Scan on resourcedetails (cost=7.65..528.27 rows=434 width=8) (actual time=0.128..448.495 rows=19 loops=1)
Recheck Cond: (resourcegroupid = 132)
-> Bitmap Index Scan on resourcedetails_rg_idx (cost=0.00..7.54 rows=434 width=0) (actual time=0.103..0.103 rows=63 loops=1)
Index Cond: (resourcegroupid = 132)
Total runtime: 7058.156 ms
(17 rows)
After postgres restart, the problem was resolved and here is the output:
(This time with all options of explain)
<pre>
explain (analyze,buffers,costs,timing,verbose) SELECT s.severity, s.severityid from SEVERITY s where s.severityid =(select MIN(severityid) from ALARM a, (SELECT * FROM RESOURCEDETAILS) as RESOURCEDETAILS WHERE RESOURCEDETAILS.resourcegroupid = 132 AND RESOURCEDETAILS.resourceid = a.resourceid AND a.severityid <> 1 AND a.severityid <> 2 AND a.severityid <> 7);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------
Seq Scan on public.severity s (cost=4516.93..4518.02 rows=1 width=13) (actual time=15.881..15.882 rows=1 loops=1)
Output: s.severity, s.severityid
Filter: (s.severityid = $0)
Rows Removed by Filter: 6
Buffers: shared hit=3167
InitPlan 1 (returns $0)
-> Aggregate (cost=4516.92..4516.93 rows=1 width=8) (actual time=15.874..15.875 rows=1 loops=1)
Output: min(a.severityid)
Buffers: shared hit=3166
-> Hash Join (cost=520.61..4516.91 rows=5 width=8) (actual time=7.043..15.869 rows=2 loops=1)
Output: a.severityid
Hash Cond: (a.resourceid = resourcedetails.resourceid)
Buffers: shared hit=3166
-> Seq Scan on public.alarm a (cost=0.00..3995.37 rows=232 width=16) (actual time=0.142..15.492 rows=108 loops=1)
Output: a.alarmid, a.eventtypeid, a.severityid, a.source, a.resourceid, a.componentid, a.category, a.createdtime, a.updatedtime, a.owner, a.ackstatus, a.acktime, a.clearedtime, a.messa
ge, a.remedy, a.optionalfield, a.version
Filter: ((a.severityid <> 1) AND (a.severityid <> 2) AND (a.severityid <> 7))
Rows Removed by Filter: 26130
Buffers: shared hit=3108
-> Hash (cost=515.39..515.39 rows=418 width=8) (actual time=0.338..0.338 rows=19 loops=1)
Output: resourcedetails.resourceid
Buckets: 1024 Batches: 1 Memory Usage: 1kB
Buffers: shared hit=58
-> Bitmap Heap Scan on public.resourcedetails (cost=7.53..515.39 rows=418 width=8) (actual time=0.033..0.330 rows=19 loops=1)
Output: resourcedetails.resourceid
Recheck Cond: (resourcedetails.resourcegroupid = 132)
Buffers: shared hit=58
-> Bitmap Index Scan on resourcedetails_rg_idx (cost=0.00..7.42 rows=418 width=0) (actual time=0.023..0.023 rows=61 loops=1)
Index Cond: (resourcedetails.resourcegroupid = 132)
Buffers: shared hit=3
Total runtime: 15.937 ms
(30 rows)
After postgresql restart, the query seems to deteriorate steadily...
posgtres version 9.1.9
Following query produces different plan when run in two different databases.
explain (analyze,buffers) SELECT group_.groupid AS groupId,
group_.name AS groupName,
group_.type_ AS groupType,
group_.friendlyurl AS groupFriendlyURL
FROM group_
inner join groups_orgs
ON ( groups_orgs.groupid = group_.groupid )
inner join users_orgs
ON ( users_orgs.organizationid = groups_orgs.organizationid )
WHERE ( group_.livegroupid = 0 )
AND ( users_orgs.userid = '27091470' )
AND ( group_.companyid = '20002' )
AND ( group_.classnameid = 10001
OR group_.classnameid = 10003 )
AND ( group_.name != 'Control Panel' )
AND ( group_.type_ != 4 )
;
Plan from Production database.
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Merge Join (cost=6.36..16.60 rows=1 width=37) (actual time=0.133..95.323 rows=3 loops=1)
Merge Cond: (group_.groupid = groups_orgs.groupid)
Buffers: shared hit=30829
-> Index Scan using group__pkey on group_ (cost=0.00..87997.62 rows=17244 width=37) (actual time=0.030..85.166 rows=13906 loops=1)
Filter: (((name)::text <> 'Control Panel'::text) AND (type_ <> 4) AND (livegroupid = 0) AND (companyid = 20002::bigint) AND ((classnameid = 10001) OR (classnameid = 10003)))
Buffers: shared hit=30824
-> Sort (cost=6.36..6.37 rows=3 width=8) (actual time=0.076..0.079 rows=3 loops=1)
Sort Key: groups_orgs.groupid
Sort Method: quicksort Memory: 25kB
Buffers: shared hit=5
-> Merge Join (cost=1.05..6.34 rows=3 width=8) (actual time=0.045..0.054 rows=3 loops=1)
Merge Cond: (users_orgs.organizationid = groups_orgs.organizationid)
Buffers: shared hit=5
-> Index Scan using users_orgs_pkey on users_orgs (cost=0.00..10.47 rows=2 width=8) (actual time=0.012..0.014 rows=2 loops=1)
Index Cond: (userid = 27091470::bigint)
Buffers: shared hit=4
-> Sort (cost=1.05..1.06 rows=3 width=16) (actual time=0.028..0.030 rows=3 loops=1)
Sort Key: groups_orgs.organizationid
Sort Method: quicksort Memory: 25kB
Buffers: shared hit=1
-> Seq Scan on groups_orgs (cost=0.00..1.03 rows=3 width=16) (actual time=0.003..0.005 rows=3 loops=1)
Buffers: shared hit=1
Plan from database which is created by exporting/importing data from production
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..18.19 rows=1 width=36) (actual time=0.053..0.104 rows=3 loops=1)
Buffers: shared hit=18
-> Nested Loop (cost=0.00..9.77 rows=1 width=8) (actual time=0.036..0.065 rows=3 loops=1)
Join Filter: (groups_orgs.organizationid = users_orgs.organizationid)
Buffers: shared hit=6
-> Seq Scan on groups_orgs (cost=0.00..1.03 rows=3 width=16) (actual time=0.007..0.010 rows=3 loops=1)
Buffers: shared hit=1
-> Materialize (cost=0.00..8.66 rows=2 width=8) (actual time=0.008..0.012 rows=3 loops=3)
Buffers: shared hit=5
-> Index Scan using ix_fb646ca6 on users_orgs (cost=0.00..8.65 rows=2 width=8) (actual time=0.016..0.021 rows=3 loops=1)
Index Cond: (userid = 27091470::bigint)
Buffers: shared hit=5
-> Index Scan using group__pkey on group_ (cost=0.00..8.41 rows=1 width=36) (actual time=0.008..0.010 rows=1 loops=3)
Index Cond: (groupid = groups_orgs.groupid)
Filter: (((name)::text <> 'Control Panel'::text) AND (type_ <> 4) AND (livegroupid = 0) AND (companyid = 20002::bigint) AND ((classnameid = 10001) OR (classnameid = 10003)))
Buffers: shared hit=12
Production query takes around 100ms and in other DB takes 0.1ms
Difference seems to be slow index scan on group_ table (Index Scan using group__pkey on group_)
Can anyone explain the difference in execution time?
Tables in production are regularly vacuumed and analyzed.
Production DB is more busy than other DB.
Thanks,
Sameer
I was facing the same issue, in the "backup" database a query was blazing fast, and the same query when run in the production database was horribly slow. It turns out I only needed to perform Routine Database Maintenance Tasks more often to solve the problem:
The PostgreSQL query planner relies on statistical information about the contents of tables in order to generate good plans for queries. These statistics are gathered by the ANALYZE command, which can be invoked by itself or as an optional step in VACUUM. It is important to have reasonably accurate statistics, otherwise poor choices of plans may degrade database performance.
So if you're experiencing a similar issue try running the following command on your "slow" database:
$ vacuumdb --host localhost --port 5432 --username "MyUser" -d "MyDatabase" --analyze --verbose