Hi, We recently upgraded our database from 9.1 to 9.6. We are seeing some unusual slow queries after the upgrade. Sometimes the queries are faster after vacuum analyze, but not consistent. We tried with different settings of random_page_cost, work_mem, effective_cache_size but the query results are the same. I am trying to understand if changing the queries/indexes would give us better performance. Please provide your suggestions. Below is our table,index definition. Table : cm_ci_relations Column | Type | Modifiers | Storage | Stats target | Description ---------------------+-----------------------------+----------------------- -+----------+--------------+------------- ci_relation_id | bigint | not null | plain | | ns_id | bigint | not null | plain | 200 | from_ci_id | bigint | not null | plain | | relation_goid | character varying(256) | not null | extended | | relation_id | integer | not null | plain | | to_ci_id | bigint | not null | plain | | ci_state_id | integer | not null | plain | | last_applied_rfc_id | bigint | | plain | | comments | character varying(2000) | | extended | | created_by | character varying(200) | | extended | | update_by | character varying(200) | | extended | | created | timestamp without time zone | not null default now() | plain | | updated | timestamp without time zone | not null default now() | plain | | Indexes: "cm_ci_relations_pk" PRIMARY KEY, btree (ci_relation_id) "cm_ci_relations_goid_idx" UNIQUE, btree (relation_goid) "cm_ci_relations_uniq_idx" UNIQUE, btree (from_ci_id, relation_id, to_ci_id) "cm_ci_relations_fromci_idx" btree (from_ci_id) "cm_ci_relations_ns_idx" btree (ns_id) "cm_ci_relations_r_ns_idx" btree (relation_id, ns_id) "cm_ci_relations_toci_idx" btree (to_ci_id) Table : ns_namespaces Column | Type | Modifiers | Storage | Stats target | Description ---------+-----------------------------+------------------------+---------- +--------------+------------- ns_id | bigint | not null | plain | | ns_path | character varying(200) | not null | extended | 300 | created | timestamp without time zone | not null default now() | plain | | Indexes: "ns_namespaces_pk" PRIMARY KEY, btree (ns_id) "ns_namespaces_ak" UNIQUE, btree (ns_path) "ns_namespaces_vpo" btree (ns_path varchar_pattern_ops) Table : cm_ci Column | Type | Modifiers | Storage | Stats target | Description ---------------------+-----------------------------+----------------------- -+----------+--------------+------------- ci_id | bigint | not null | plain | | ns_id | bigint | not null | plain | | class_id | integer | not null | plain | | ci_name | character varying(200) | not null | extended | | ci_goid | character varying(256) | not null | extended | | comments | character varying(2000) | | extended | | ci_state_id | integer | not null | plain | | last_applied_rfc_id | bigint | | plain | | created_by | character varying(200) | | extended | | updated_by | character varying(200) | | extended | | created | timestamp without time zone | not null default now() | plain | | updated | timestamp without time zone | not null default now() | plain | | Indexes: "cm_ci_pk" PRIMARY KEY, btree (ci_id) "cm_ci_3cols_idx" UNIQUE, btree (ns_id, class_id, ci_name) "df_ci_goid_idx" UNIQUE, btree (ci_goid) "cm_ci_cl_idx" btree (class_id) "cm_ci_ns_idx" btree (ns_id) Table : md_relations Column | Type | Modifiers | Storage | Stats target | Description ---------------------+-----------------------------+----------------------- -+----------+--------------+------------- relation_id | integer | not null | plain | | relation_name | character varying(200) | not null | extended | | short_relation_name | character varying(200) | not null | extended | | description | text | not null | extended | | created | timestamp without time zone | not null default now() | plain | | Indexes: "md_relations_pk" PRIMARY KEY, btree (relation_id) "md_relations_rln_idx" UNIQUE, btree (relation_name) "md_relations_srn_idx" btree (short_relation_name) Table : md_classes Table "kloopzcm.md_classes" Column | Type | Modifiers | Storage | Stats target | Description ------------------+-----------------------------+------------------------+- ---------+--------------+------------- class_id | integer | not null | plain | | class_name | character varying(200) | not null | extended | | short_class_name | character varying(200) | not null | extended | | super_class_id | integer | | plain | | is_namespace | boolean | not null | plain | | flags | integer | not null default 0 | plain | | impl | character varying(200) | | extended | | access_level | character varying(200) | | extended | | description | text | | extended | | format | text | | extended | | created | timestamp without time zone | not null default now() | plain | | Indexes: "md_classes_pk" PRIMARY KEY, btree (class_id) "md_classes_cln_idx" UNIQUE, btree (class_name) "md_classes_comp_names_idx" btree (class_name, short_class_name) "md_classes_scln_idx" btree (short_class_name) Table : cm_ci_state Column | Type | Modifiers | Storage | Stats target | Description -------------+-----------------------+-----------+----------+-------------- +------------- ci_state_id | integer | not null | plain | | state_name | character varying(64) | not null | extended | | Indexes: "cm_ci_state_pk" PRIMARY KEY, btree (ci_state_id) The below query has been really slow after the upgrade, the explain plan shows that it uses the cm_ci_relations_fromci_idx index on the cm_ci_relations table. But when another set of parameters are used for the ns_path the query plan is better. In general I expect the ns_namespaces, md_relations being queried first and then the results are further used on the cm_ci_relations_r_ns_idx index (cm_ci_relations table) and then cm_ci table. That would filter out a lot of records and will be much faster. Table Data ---------- The ns_namespaces table contains data like a folder structure and can go upto five levels separated by slash /f1/f2/f3/f4/f5 /f1/f2/a1 /f1/f2/b1 /f1/c1 /g1/b1 There would be a lot of duplicates matching the beginning section of the path. cm_ci is the instances table with around 3 million records; cm_ci_relations is the relations between instances table, with around 7.5 million records. this table is the largest in this query. md_classes contains around 2k records md_relations contains around 100+ records Its not that the longer the ns_path parameter provided, the query is faster. In some cases where the ns_path parameter is very much focused like (/a/b/c/d/e) with different relation names and class names the query was still slow as the planner was not using the best possible index cm_ci_relations_r_ns_idx. slow performing query: explain (buffers, analyze) select cir.ci_relation_id as ciRelationId, cir.ns_id as nsId, ns.ns_path as nsPath, cir.from_ci_id as fromCiId, cir.relation_goid as relationGoid, cir.relation_id as relationId, mdr.relation_name as relationName, cir.to_ci_id toCiId, cir.ci_state_id as relationStateId, cis.state_name as relationState, cir.last_applied_rfc_id as lastAppliedRfcId, cir.comments, cir.created, cir.updated from cm_ci_relations cir, md_relations mdr, cm_ci_state cis, cm_ci from_ci, md_classes from_mdc, cm_ci to_ci, md_classes to_mdc, ns_namespaces ns where (ns.ns_path like '/test1/%' or ns.ns_path = '/test1') and cir.ns_id = ns.ns_id and cir.ci_state_id = cis.ci_state_id and cir.relation_id = mdr.relation_id and (mdr.relation_name = 'base.DeployedTo') and cir.from_ci_id = from_ci.ci_id and from_ci.class_id = from_mdc.class_id and ( from_mdc.class_name = 'bom.Compute') and cir.to_ci_id = to_ci.ci_id and to_ci.class_id = to_mdc.class_id; below is the explain plan for this query QUERY PLAN --------------------------------------------------------------------------- ----------------------------------------------------------------- ----------------------------------------------- Nested Loop (cost=139.97..18932.15 rows=1 width=288) (actual time=63.741..7213.251 rows=276 loops=1) Buffers: shared hit=552715 read=6114 -> Nested Loop (cost=139.69..18931.84 rows=1 width=292) (actual time=63.675..7211.745 rows=276 loops=1) Buffers: shared hit=552162 read=6114 -> Nested Loop (cost=139.26..18931.35 rows=1 width=288) (actual time=63.646..7206.066 rows=276 loops=1) Buffers: shared hit=551058 read=6114 -> Nested Loop (cost=139.12..18931.19 rows=1 width=277) (actual time=63.637..7199.116 rows=276 loops=1) Buffers: shared hit=550506 read=6114 -> Nested Loop (cost=138.70..18919.38 rows=26 width=228) (actual time=58.446..6620.992 rows=62689 loops=1) Join Filter: (cir.relation_id = mdr.relation_id) Rows Removed by Join Filter: 125384 Buffers: shared hit=299270 read=6114 -> Seq Scan on md_relations mdr (cost=0.00..7.59 rows=1 width=22) (actual time=0.017..0.060 rows=1 loops=1) Filter: ((relation_name)::text = 'base.DeployedTo'::text) Rows Removed by Filter: 126 Buffers: shared hit=6 -> Nested Loop (cost=138.70..18869.86 rows=3355 width=210) (actual time=58.418..6551.520 rows=188073 loops=1) Buffers: shared hit=299264 read=6114 -> Nested Loop (cost=138.27..17306.08 rows=1271 width=8) (actual time=58.367..1012.918 rows=62710 loops=1 ) Buffers: shared hit=28631 -> Index Scan using md_classes_comp_names_idx on md_classes from_mdc (cost=0.28..8.30 rows=1 width= 4) (actual time=0.031..0.037 rows=1 loops=1) Index Cond: ((class_name)::text = 'bom.Compute'::text) Buffers: shared hit=3 -> Bitmap Heap Scan on cm_ci from_ci (cost=137.99..17238.99 rows=5879 width=12) (actual time=58.332 ..980.258 rows=62710 loops=1) Recheck Cond: (class_id = from_mdc.class_id) Heap Blocks: exact=28001 Buffers: shared hit=28628 -> Bitmap Index Scan on cm_ci_cl_idx (cost=0.00..136.52 rows=5879 width=0) (actual time=52.52 0..52.520 rows=63497 loops=1) Index Cond: (class_id = from_mdc.class_id) Buffers: shared hit=627 -> Index Scan using cm_ci_relations_fromci_idx on cm_ci_relations cir (cost=0.43..1.07 rows=16 width=210) (actual time=0.067..0.084 rows=3 loops=62710) Index Cond: (from_ci_id = from_ci.ci_id) Buffers: shared hit=270633 read=6114 -> Index Scan using ns_namespaces_pk on ns_namespaces ns (cost=0.42..0.44 rows=1 width=57) (actual time=0.008..0.008 rows=0 loops=62689) Index Cond: (ns_id = cir.ns_id) Filter: (((ns_path)::text ~~ '/test1/%'::text) OR ((ns_path)::text = '/test1'::text)) Rows Removed by Filter: 1 Buffers: shared hit=251236 -> Index Scan using cm_ci_state_pk on cm_ci_state cis (cost=0.13..0.15 rows=1 width=15) (actual time=0.002..0.003 rows=1 lo ops=276) Index Cond: (ci_state_id = cir.ci_state_id) Buffers: shared hit=552 -> Index Scan using cm_ci_pk on cm_ci to_ci (cost=0.43..0.48 rows=1 width=12) (actual time=0.015..0.016 rows=1 loops=276) Index Cond: (ci_id = cir.to_ci_id) Buffers: shared hit=1104 -> Index Only Scan using md_classes_pk on md_classes to_mdc (cost=0.28..0.30 rows=1 width=4) (actual time=0.003..0.004 rows=1 loops=276 ) Index Cond: (class_id = to_ci.class_id) Heap Fetches: 0 Buffers: shared hit=553 Planning time: 12.641 ms Execution time: 7214.707 ms similar query with different parameters, this gets executed much faster explain (buffers, analyze) select cir.ci_relation_id as ciRelationId, cir.ns_id as nsId, ns.ns_path as nsPath, cir.from_ci_id as fromCiId, cir.relation_goid as relationGoid, cir.relation_id as relationId, mdr.relation_name as relationName, cir.to_ci_id toCiId, cir.ci_state_id as relationStateId, cis.state_name as relationState, cir.last_applied_rfc_id as lastAppliedRfcId, cir.comments, cir.created, cir.updated from cm_ci_relations cir, md_relations mdr, cm_ci_state cis, cm_ci from_ci, md_classes from_mdc, cm_ci to_ci, md_classes to_mdc, ns_namespaces ns where (ns.ns_path like '/test1/test2/%' or ns.ns_path = '/test1/test2') and cir.ns_id = ns.ns_id and cir.ci_state_id = cis.ci_state_id and cir.relation_id = mdr.relation_id and (mdr.relation_name = 'base.DeployedTo') and cir.from_ci_id = from_ci.ci_id and from_ci.class_id = from_mdc.class_id and ( from_mdc.class_name = 'bom.Compute') and cir.to_ci_id = to_ci.ci_id and to_ci.class_id = to_mdc.class_id; QUERY PLAN --------------------------------------------------------------------------- ----------------------------------------------------------------- -------------------------------------------------- Nested Loop (cost=10.72..479.62 rows=1 width=288) (actual time=5.101..98.016 rows=114 loops=1) Buffers: shared hit=13321 read=31 -> Nested Loop (cost=10.44..479.31 rows=1 width=292) (actual time=5.068..97.647 rows=114 loops=1) Buffers: shared hit=13092 read=31 -> Nested Loop (cost=10.01..478.82 rows=1 width=288) (actual time=5.037..94.108 rows=114 loops=1) Join Filter: (cir.ci_state_id = cis.ci_state_id) Rows Removed by Join Filter: 456 Buffers: shared hit=12636 read=31 -> Nested Loop (cost=10.01..477.71 rows=1 width=277) (actual time=5.030..93.568 rows=114 loops=1) Buffers: shared hit=12522 read=31 -> Nested Loop (cost=9.73..475.54 rows=7 width=281) (actual time=0.383..87.509 rows=1578 loops=1) Buffers: shared hit=7788 read=31 -> Nested Loop (cost=9.30..472.10 rows=7 width=277) (actual time=0.362..53.412 rows=1578 loops=1) Buffers: shared hit=1475 read=26 -> Seq Scan on md_relations mdr (cost=0.00..7.59 rows=1 width=22) (actual time=0.014..0.037 rows=1 loops= 1) Filter: ((relation_name)::text = 'base.DeployedTo'::text) Rows Removed by Filter: 126 Buffers: shared hit=6 -> Nested Loop (cost=9.30..463.63 rows=88 width=259) (actual time=0.333..52.719 rows=1578 loops=1) Buffers: shared hit=1469 read=26 -> Bitmap Heap Scan on ns_namespaces ns (cost=8.87..12.88 rows=22 width=57) (actual time=0.202..0.4 51 rows=119 loops=1) Recheck Cond: (((ns_path)::text ~~ '/test1/test2/%'::text) OR ((ns_path)::text = '/test1/test2' ::text)) Filter: (((ns_path)::text ~~ '/test1/test2/%'::text) OR ((ns_path)::text = '/test1/test2'::text )) Heap Blocks: exact=48 Buffers: shared hit=54 read=1 -> BitmapOr (cost=8.87..8.87 rows=1 width=0) (actual time=0.187..0.187 rows=0 loops=1) Buffers: shared hit=6 read=1 -> Bitmap Index Scan on ns_namespaces_vpo (cost=0.00..4.43 rows=1 width=0) (actual time =0.181..0.181 rows=118 loops=1) Index Cond: (((ns_path)::text ~>=~ '/test1/test2/'::text) AND ((ns_path)::text ~<~ '/test1/test20'::text)) Buffers: shared hit=3 read=1 -> Bitmap Index Scan on ns_namespaces_vpo (cost=0.00..4.43 rows=1 width=0) (actual time =0.004..0.004 rows=1 loops=1) Index Cond: ((ns_path)::text = '/test1/test2'::text) Buffers: shared hit=3 -> Index Scan using cm_ci_relations_r_ns_idx on cm_ci_relations cir (cost=0.43..20.45 rows=4 width= 210) (actual time=0.010..0.429 rows=13 loops=119) Index Cond: ((relation_id = mdr.relation_id) AND (ns_id = ns.ns_id)) Buffers: shared hit=1415 read=25 -> Index Scan using cm_ci_pk on cm_ci from_ci (cost=0.43..0.48 rows=1 width=12) (actual time=0.020..0.020 rows= 1 loops=1578) Index Cond: (ci_id = cir.from_ci_id) Buffers: shared hit=6313 read=5 -> Index Scan using md_classes_pk on md_classes from_mdc (cost=0.28..0.30 rows=1 width=4) (actual time=0.003..0.003 r ows=0 loops=1578) Index Cond: (class_id = from_ci.class_id) Filter: ((class_name)::text = 'bom.Compute'::text) Rows Removed by Filter: 1 Buffers: shared hit=4734 -> Seq Scan on cm_ci_state cis (cost=0.00..1.05 rows=5 width=15) (actual time=0.001..0.002 rows=5 loops=114) Buffers: shared hit=114 -> Index Scan using cm_ci_pk on cm_ci to_ci (cost=0.43..0.48 rows=1 width=12) (actual time=0.030..0.030 rows=1 loops=114) Index Cond: (ci_id = cir.to_ci_id) Buffers: shared hit=456 -> Index Only Scan using md_classes_pk on md_classes to_mdc (cost=0.28..0.30 rows=1 width=4) (actual time=0.002..0.002 rows=1 loops=114 ) Index Cond: (class_id = to_ci.class_id) Heap Fetches: 0 Buffers: shared hit=229 Planning time: 8.468 ms Execution time: 98.223 ms Thanks, Bhaskar -- Sent via pgsql-performance mailing list (pgsql-performance@xxxxxxxxxxxxxx) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-performance