Postgresql Table Partition - database
I have a query regarding my query performance
I am partitioning a table on daily basis
The table creation script is mentioned below:
-- Table: myschema."auditrtailreference_2014-10-02"
-- DROP TABLE myschema."auditrtailreference_2014-10-02";
CREATE TABLE myschema."auditrtailreference_2014-10-02"
(
-- Inherited from table myschema.auditrtailreference: event smallint,
-- Inherited from table myschema.auditrtailreference: innodeid character varying(80),
-- Inherited from table myschema.auditrtailreference: innodename character varying(80),
-- Inherited from table myschema.auditrtailreference: sourceid character varying(300),
-- Inherited from table myschema.auditrtailreference: intime timestamp without time zone,
-- Inherited from table myschema.auditrtailreference: outnodeid character varying(80),
-- Inherited from table myschema.auditrtailreference: outnodename character varying(80),
-- Inherited from table myschema.auditrtailreference: destinationid character varying(300),
-- Inherited from table myschema.auditrtailreference: outtime timestamp without time zone,
-- Inherited from table myschema.auditrtailreference: bytes integer,
-- Inherited from table myschema.auditrtailreference: cdrs integer,
-- Inherited from table myschema.auditrtailreference: noofsubfilesinfile integer,
-- Inherited from table myschema.auditrtailreference: recordsequencenumberlist character varying(1000),
-- Inherited from table myschema.auditrtailreference: partial_cdrs integer,
-- Inherited from table myschema.auditrtailreference: duplicate_cdrs integer,
-- Inherited from table myschema.auditrtailreference: discarded_cdrs integer,
-- Inherited from table myschema.auditrtailreference: created_cdrs integer,
-- Inherited from table myschema.auditrtailreference: corrupted_cdrs integer,
-- Inherited from table myschema.auditrtailreference: created_files integer,
-- Inherited from table myschema.auditrtailreference: duplicate_files integer,
-- Inherited from table myschema.auditrtailreference: corrupted_files integer,
-- Inherited from table myschema.auditrtailreference: partial_files integer,
-- Inherited from table myschema.auditrtailreference: discarded_files integer,
-- Inherited from table myschema.auditrtailreference: empty_files integer,
CONSTRAINT "auditrtailreference_2014-10-02_intime_check" CHECK (intime >= '2014-10-02 00:00:00'::timestamp without time zone AND intime < '2014-10-03 00:00:00'::timestamp without time zone OR intime IS NULL),
CONSTRAINT "auditrtailreference_2014-10-02_outtime_check" CHECK (outtime >= '2014-10-02 00:00:00'::timestamp without time zone AND outtime < '2014-10-03 00:00:00'::timestamp without time zone OR outtime IS NULL)
)
INHERITS (myschema.auditrtailreference)
WITH (
OIDS=FALSE
);
ALTER TABLE myschema."auditrtailreference_2014-10-02"
OWNER TO erix;
-- Index: myschema."auditrtailreference_2014-10-02_dest_indx1"
-- DROP INDEX myschema."auditrtailreference_2014-10-02_dest_indx1";
CREATE INDEX "auditrtailreference_2014-10-02_dest_indx1"
ON myschema."auditrtailreference_2014-10-02"
USING btree
(destinationid COLLATE pg_catalog."default" );
-- Index: myschema."auditrtailreference_2014-10-02_in_indx1"
-- DROP INDEX myschema."auditrtailreference_2014-10-02_in_indx1";
CREATE INDEX "auditrtailreference_2014-10-02_in_indx1"
ON myschema."auditrtailreference_2014-10-02"
USING btree
(intime );
-- Index: myschema."auditrtailreference_2014-10-02_out_indx1"
-- DROP INDEX myschema."auditrtailreference_2014-10-02_out_indx1";
CREATE INDEX "auditrtailreference_2014-10-02_out_indx1"
ON myschema."auditrtailreference_2014-10-02"
USING btree
(outtime );
-- Index: myschema."auditrtailreference_2014-10-02_srce_indx1"
-- DROP INDEX myschema."auditrtailreference_2014-10-02_srce_indx1";
CREATE INDEX "auditrtailreference_2014-10-02_srce_indx1"
ON myschema."auditrtailreference_2014-10-02"
USING btree
(sourceid COLLATE pg_catalog."default" );
My Query for the data fetch is as follows
select t3.destinationid as input, t1.sourceid as Raw, t1.outtime::text, t7.destinationid, t7.outtime::text as output from myschema.auditrtailreference t1
LEFT JOIN myschema.auditrtailreference t2 on t2.sourceid = t1.destinationid AND t2.event ='80' and t2.outnodename not like '%CRS%' and t2.outnodename not like '%rch' and t2.outtime between '2014/12/11' AND '2014/12/12'
LEFT JOIN myschema.auditrtailreference t3 on t3.sourceid = t2.destinationid AND t3.event ='68' and t3.outtime between '2014/12/11' AND '2014/12/12'
LEFT JOIN myschema.auditrtailreference t4 on t4.sourceid = t3.destinationid AND t4.event ='67' and t4.innodename like 'AIR%ollect%r' and t4.outtime >= t3.outtime and t4.outtime between '2014/12/11' AND '2014/12/12'
LEFT JOIN myschema.auditrtailreference t5 on t5.sourceid = t4.destinationid AND t5.event ='80' and t5.outnodename not like '%ESB%' and t5.outnodename not like '%Type' and t5.outtime between '2014/12/11' AND '2014/12/12'
LEFT JOIN myschema.auditrtailreference t6 on t6.sourceid = t5.destinationid AND t6.event ='68' and t6.outtime between '2014/12/11' AND '2014/12/12'
LEFT JOIN myschema.auditrtailreference t7 on (t7.destinationid = t6.destinationid || '.gz' OR t7.destinationid = t6.destinationid OR t7.destinationid = t6.destinationid || '.csv') AND t7.event ='68' AND (t7.outnodename like '%AIR%_distributer' or t7.outnodename like '%AIR%_Arch' or t7.outnodename like '%AIR%_Distributer' or t7.outnodename like '%AIR%_Distributor' or t7.outnodename like '%AIR%_distributor') and t7.outtime between '2014/12/11' AND '2014/12/12'
where t1.event ='67' and t1.innodename like 'AIR%FTP' and t1.sourceid not like '%my%' and t1.intime >= '2014/12/11 00:00:00' and t1.intime <= '2014/12/11 23:59:59' AND t3.destinationid like '%';
I am facing the issue with the table performance
Could someone please help me with this
Thanks a ton in Advance
Explain Analyze for the above query is as follows
Merge Right Join (cost=2230028197.24..10806551039995472.00 rows=432260982728698432 width=136) (actual time=597187.343..1059019.252 rows=3400 loops=1)
Merge Cond: ((t5.sourceid)::text = (t4.destinationid)::text)
-> Nested Loop Left Join (cost=0.03..24192368907.34 rows=14433968717 width=86) (actual time=679.865..1054884.883 rows=353487 loops=1)
Join Filter: (((t7.destinationid)::text = ((t6.destinationid)::text || '.gz'::text)) OR ((t7.destinationid)::text = (t6.destinationid)::text) OR ((t7.destinationid)::text = ((t6.destinationid)::text || '.csv'::text)))
-> Nested Loop Left Join (cost=0.03..15009299.32 rows=497219528 width=78) (actual time=184.474..13354.447 rows=353487 loops=1)
Join Filter: ((t6.sourceid)::text = (t5.destinationid)::text)
-> Merge Append (cost=0.03..7883009.19 rows=311384 width=78) (actual time=184.415..1877.546 rows=353487 loops=1)
Sort Key: t5.sourceid
-> Sort (cost=0.01..0.02 rows=1 width=336) (actual time=0.030..0.030 rows=0 loops=1)
Sort Key: t5.sourceid
Sort Method: quicksort Memory: 25kB
-> Seq Scan on auditrtailreference t5 (cost=0.00..0.00 rows=1 width=336) (actual time=0.001..0.001 rows=0 loops=1)
Filter: (((outnodename)::text !~~ '%ESB%'::text) AND ((outnodename)::text !~~ '%Type'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
-> Index Scan using "auditrtailreference_2014-12-11_srce_indx1" on "auditrtailreference_2014-12-11" t5 (cost=0.00..3842492.30 rows=311382 width=78) (actual time=99.449..896.976 rows=353478 loops=1)
Filter: (((outnodename)::text !~~ '%ESB%'::text) AND ((outnodename)::text !~~ '%Type'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
-> Index Scan using "auditrtailreference_2014-12-12_srce_indx1" on "auditrtailreference_2014-12-12" t5 (cost=0.00..4034803.06 rows=1 width=78) (actual time=84.927..699.589 rows=9 loops=1)
Filter: (((outnodename)::text !~~ '%ESB%'::text) AND ((outnodename)::text !~~ '%Type'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
-> Append (cost=0.00..22.85 rows=3 width=164) (actual time=0.006..0.025 rows=12 loops=353487)
-> Seq Scan on auditrtailreference t6 (cost=0.00..0.00 rows=1 width=336) (actual time=0.000..0.000 rows=0 loops=353487)
Filter: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 68::smallint))
-> Index Scan using "auditrtailreference_2014-12-11_srce_indx1" on "auditrtailreference_2014-12-11" t6 (cost=0.00..15.15 rows=1 width=78) (actual time=0.004..0.005 rows=1 loops=353487)
Index Cond: ((sourceid)::text = (t5.destinationid)::text)
Filter: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 68::smallint))
-> Index Scan using "auditrtailreference_2014-12-12_out_indx1" on "auditrtailreference_2014-12-12" t6 (cost=0.00..7.70 rows=1 width=78) (actual time=0.006..0.012 rows=11 loops=353486)
Index Cond: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone))
Filter: (event = 68::smallint)
-> Materialize (cost=0.00..60063.89 rows=1945 width=50) (actual time=0.000..0.982 rows=3400 loops=353487)
-> Append (cost=0.00..60054.16 rows=1945 width=50) (actual time=0.570..489.242 rows=3400 loops=1)
-> Seq Scan on auditrtailreference t7 (cost=0.00..0.00 rows=1 width=176) (actual time=0.001..0.001 rows=0 loops=1)
Filter: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 68::smallint) AND (((outnodename)::text ~~ '%AIR%_distributer'::text) OR ((outnodename)::text ~~ '%AIR%_Arch'::text) OR ((outnodename)::text ~~ '%AIR%_Distributer'::text) OR ((outnodename)::text ~~ '%AIR%_Distributor'::text) OR ((outnodename)::text ~~ '%AIR%_distributor'::text)))
-> Seq Scan on "auditrtailreference_2014-12-11" t7 (cost=0.00..60045.68 rows=1943 width=50) (actual time=0.568..487.333 rows=3399 loops=1)
Filter: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 68::smallint) AND (((outnodename)::text ~~ '%AIR%_distributer'::text) OR ((outnodename)::text ~~ '%AIR%_Arch'::text) OR ((outnodename)::text ~~ '%AIR%_Distributer'::text) OR ((outnodename)::text ~~ '%AIR%_Distributor'::text) OR ((outnodename)::text ~~ '%AIR%_distributor'::text)))
-> Index Scan using "auditrtailreference_2014-12-12_out_indx1" on "auditrtailreference_2014-12-12" t7 (cost=0.00..8.48 rows=1 width=50) (actual time=0.024..0.028 rows=1 loops=1)
Index Cond: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone))
Filter: ((event = 68::smallint) AND (((outnodename)::text ~~ '%AIR%_distributer'::text) OR ((outnodename)::text ~~ '%AIR%_Arch'::text) OR ((outnodename)::text ~~ '%AIR%_Distributer'::text) OR ((outnodename)::text ~~ '%AIR%_Distribu
tor'::text) OR ((outnodename)::text ~~ '%AIR%_distributor'::text)))
-> Materialize (cost=2230028197.20..2259975676.73 rows=5989495905 width=128) (actual time=3921.050..3924.851 rows=3400 loops=1)
-> Sort (cost=2230028197.20..2245001936.96 rows=5989495905 width=128) (actual time=3921.048..3922.459 rows=2576 loops=1)
Sort Key: t4.destinationid
Sort Method: quicksort Memory: 781kB
-> Merge Join (cost=591325.77..90441565.36 rows=5989495905 width=128) (actual time=3784.636..3918.059 rows=2576 loops=1)
Merge Cond: ((t3.sourceid)::text = (t2.destinationid)::text)
-> Sort (cost=308087.95..310241.46 rows=861404 width=120) (actual time=3464.384..3557.638 rows=150872 loops=1)
Sort Key: t3.sourceid
Sort Method: external merge Disk: 35784kB
-> Merge Left Join (cost=123584.91..170172.32 rows=861404 width=120) (actual time=2003.668..2499.298 rows=373330 loops=1)
Merge Cond: ((t3.destinationid)::text = (t4.sourceid)::text)
Join Filter: (t4.outtime >= t3.outtime)
-> Sort (cost=74053.15..74735.00 rows=272740 width=86) (actual time=1798.163..2042.079 rows=373330 loops=1)
Sort Key: t3.destinationid
Sort Method: external merge Disk: 39896kB
-> Append (cost=0.00..49428.59 rows=272740 width=86) (actual time=0.013..785.277 rows=373330 loops=1)
-> Seq Scan on auditrtailreference t3 (cost=0.00..0.00 rows=1 width=344) (actual time=0.001..0.001 rows=0 loops=1)
Filter: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND ((destinationid)::text ~~ '%'::text) AND (event = 68::smallint))
-> Seq Scan on "auditrtailreference_2014-12-11" t3 (cost=0.00..49420.12 rows=272738 width=86) (actual time=0.010..570.958 rows=373319 loops=1)
Filter: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND ((destinationid)::text ~~ '%'::text) AND (event = 68::smallint
))
-> Index Scan using "auditrtailreference_2014-12-12_out_indx1" on "auditrtailreference_2014-12-12" t3 (cost=0.00..8.47 rows=1 width=86) (actual time=0.021..0.030 rows=11 loops=1)
Index Cond: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone))
Filter: (((destinationid)::text ~~ '%'::text) AND (event = 68::smallint))
-> Sort (cost=49531.76..49536.49 rows=1895 width=86) (actual time=205.498..207.953 rows=7726 loops=1)
Sort Key: t4.sourceid
Sort Method: quicksort Memory: 459kB
-> Append (cost=0.00..49428.59 rows=1895 width=86) (actual time=0.251..202.613 rows=2576 loops=1)
-> Seq Scan on auditrtailreference t4 (cost=0.00..0.00 rows=1 width=344) (actual time=0.001..0.001 rows=0 loops=1)
Filter: (((innodename)::text ~~ 'AIR%ollect%r'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 67::smallint))
-> Seq Scan on "auditrtailreference_2014-12-11" t4 (cost=0.00..49420.12 rows=1893 width=86) (actual time=0.247..201.086 rows=2576 loops=1)
Filter: (((innodename)::text ~~ 'AIR%ollect%r'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 67::smallint))
-> Index Scan using "auditrtailreference_2014-12-12_out_indx1" on "auditrtailreference_2014-12-12" t4 (cost=0.00..8.47 rows=1 width=86) (actual time=0.022..0.022 rows=0 loops=1)
Index Cond: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone))
Filter: (((innodename)::text ~~ 'AIR%ollect%r'::text) AND (event = 67::smallint))
-> Materialize (cost=283237.82..290191.00 rows=1390636 width=86) (actual time=299.606..302.090 rows=2576 loops=1)
-> Sort (cost=283237.82..286714.41 rows=1390636 width=86) (actual time=299.543..300.435 rows=2576 loops=1)
Sort Key: t2.destinationid
Sort Method: quicksort Memory: 459kB
-> Nested Loop (cost=0.00..74796.60 rows=1390636 width=86) (actual time=0.251..296.114 rows=2576 loops=1)
Join Filter: ((t1.destinationid)::text = (t2.sourceid)::text)
-> Append (cost=0.00..52076.51 rows=940 width=86) (actual time=0.218..202.923 rows=2576 loops=1)
-> Seq Scan on auditrtailreference t1 (cost=0.00..0.00 rows=1 width=344) (actual time=0.001..0.001 rows=0 loops=1)
Filter: (((innodename)::text ~~ 'AIR%FTP'::text) AND ((sourceid)::text !~~ '%my%'::text) AND (intime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (intime <= '2014-12-11 23:59:59'::timestamp without time zone) AND (event = 67::smallint))
-> Seq Scan on "auditrtailreference_2014-12-11" t1 (cost=0.00..52076.51 rows=939 width=86) (actual time=0.216..201.425 rows=2576 loops=1)
Filter: (((innodename)::text ~~ 'AIR%FTP'::text) AND ((sourceid)::text !~~ '%my%'::text) AND (intime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (intime <= '2014-12-11 23:59:59'::timestamp without time zone) AND (event = 67::smallint))
-> Append (cost=0.00..24.13 rows=3 width=164) (actual time=0.007..0.030 rows=11 loops=2576)
-> Seq Scan on auditrtailreference t2 (cost=0.00..0.00 rows=1 width=336) (actual time=0.000..0.000 rows=0 loops=2576)
Filter: (((outnodename)::text !~~ '%CRS%'::text) AND ((outnodename)::text !~~ %rch'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
-> Index Scan using "auditrtailreference_2014-12-11_srce_indx1" on "auditrtailreference_2014-12-11" t2 (cost=0.00..15.99 rows=1 width=78) (actual time=0.005..0.006 rows=1 loops=2576)
Index Cond: ((sourceid)::text = (t1.destinationid)::text)
Filter: (((outnodename)::text !~~ '%CRS%'::text) AND ((outnodename)::text !~~ '%rch'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
-> Index Scan using "auditrtailreference_2014-12-12_out_indx1" on "auditrtailreference_2014-12-12" t2 (cost=0.00..8.14 rows=1 width=78) (actual time=0.004..0.016 rows=10 loops=2576)
Index Cond: ((outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone))
Filter: (((outnodename)::text !~~ '%CRS%'::text) AND ((outnodename)::text !~~ '%rch'::text) AND (event = 80::smallint))
Total runtime: 1059027.764 ms
(90 rows)
You should replace conditions:
outtime between '2014/12/11' AND '2014/12/12'
with:
outtime >= '2014-12-11 00:00:00'::timestamp without time zone AND outtime < '2014-12-12 00:00:00'::timestamp without time zone
Key difference is that between operator is both side inclusive whereas your partitions are defined as left side inclusive and right side exclusive.
This causes two scans for each myschema.auditrtailreference reference in your query, which is visible in plan as:
-> Index Scan using "auditrtailreference_2014-12-11_srce_indx1" on "auditrtailreference_2014-12-11" t5 (cost=0.00..3842492.30 rows=311382 width=78) (actual time=99.449..896.976 rows=353478 loops=1)
Filter: (((outnodename)::text !~~ '%ESB%'::text) AND ((outnodename)::text !~~ '%Type'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
-> Index Scan using "auditrtailreference_2014-12-12_srce_indx1" on "auditrtailreference_2014-12-12" t5 (cost=0.00..4034803.06 rows=1 width=78) (actual time=84.927..699.589 rows=9 loops=1)
Filter: (((outnodename)::text !~~ '%ESB%'::text) AND ((outnodename)::text !~~ '%Type'::text) AND (outtime >= '2014-12-11 00:00:00'::timestamp without time zone) AND (outtime <= '2014-12-12 00:00:00'::timestamp without time zone) AND (event = 80::smallint))
Related
PostgreSQL - Not using indexes when querying multiple values along with CTE
I recently altered 'resources' table in my DB so that I can support multiple versions of resources. 'resources' Schema: I have one index on 'id' column and another one on 'parent_res_id' column. The query that I use to often is to get all relatives of the resources: WITH r2(id) AS ( SELECT r2.parent_res_id FROM resources r2 WHERE r2.id IN ( 2, 3 ) ) SELECT r.id FROM resources r WHERE ( r.id IN ( 2, 3 ) OR r.parent_res_id IN ( 2, 3 ) OR r.id IN (SELECT r2.id FROM r2) OR r.parent_res_id IN (SELECT r2.id FROM r2)) ; Though when I EXPLAIN ANALYZE this query, Postgres is doing seq scan instead of using indexes in the main query, and only using it for the CTE when I only pass one parameter in IN clause. Query Plan when only 1 param: Seq Scan on resources r (cost=8.21..21.25 rows=114 width=4) (actual time=0.077..0.078 rows=0 loops=1) Filter: ((id = 240) OR (parent_res_id = 240) OR (hashed SubPlan 2) OR (hashed SubPlan 3)) Rows Removed by Filter: 153 Buffers: shared hit=13 dirtied=1 CTE f2 -> Index Scan using resources_pkey on resources r2 (cost=0.14..8.16 rows=1 width=4) (actual time=0.010..0.010 rows=0 loops=1) Index Cond: (id = 240) Buffers: shared hit=3 dirtied=1 SubPlan 2 -> CTE Scan on r2 r2_1 (cost=0.00..0.02 rows=1 width=4) (actual time=0.011..0.011 rows=0 loops=1) Buffers: shared hit=3 dirtied=1 SubPlan 3 -> CTE Scan on r2 r2_2 (cost=0.00..0.02 rows=1 width=4) (actual time=0.000..0.000 rows=0 loops=1) Planning Time: 0.122 ms Execution Time: 0.104 ms Query Plan with two or more params: Seq Scan on resources r (cost=11.99..25.03 rows=115 width=4) (actual time=0.097..0.119 rows=11 loops=1) Filter: ((id = ANY ('{211,270}'::integer[])) OR (parent_res_id = ANY ('{211,270}'::integer[])) OR (hashed SubPlan 2) OR (hashed SubPlan 3)) Rows Removed by Filter: 142 Buffers: shared hit=20 CTE f2 -> Seq Scan on resources r2 (cost=0.00..11.90 rows=2 width=4) (actual time=0.024..0.033 rows=1 loops=1) Filter: (id = ANY ('{211,270}'::integer[])) Rows Removed by Filter: 152 Buffers: shared hit=10 SubPlan 2 -> CTE Scan on r2 r2_1 (cost=0.00..0.04 rows=2 width=4) (actual time=0.029..0.039 rows=1 loops=1) Buffers: shared hit=10 SubPlan 3 -> CTE Scan on r2 r2_2 (cost=0.00..0.04 rows=2 width=4) (actual time=0.000..0.000 rows=1 loops=1) Planning Time: 0.132 ms Execution Time: 0.152 ms What is the reason for this and could this be optimized for better performance?
Can someone help me make this SQL query more efficient?
SELECT datepart(qq, o.created_date), count(DISTINCT o.order_id), sum(o.order_margin) FROM orders o WHERE o.account_id IN (SELECT e.account_id FROM emailsegment e WHERE e.segment = 'H') AND o.created_date >= '1/1/2016' AND o.order_status = 'Shipped' GROUP BY datepart(qq, o.created_date) ORDER BY datepart(qq, o.created_date) This is taking forever to run, any ideas?
Try this: SELECT datepart(qq, o.created_date), count(DISTINCT o.order_id), sum(o.order_margin) FROM orders o INNER JOIN emailsegment e ON e.account_id = o.account_id AND e.segment = 'H' WHERE o.created_date >= '2016-01-01' AND o.order_status = 'Shipped' GROUP BY datepart(qq, o.created_date) ORDER BY datepart(qq, o.created_date)
Just several wild guesses: How many records returns following query and how long it is taking to run? SELECT e.account_id FROM emailsegment e WHERE e.segment = 'H'; It might be beneficial to create an index on account_id with filter on segment column. CREATE INDEX ix_account_id_emailsegment ON emailsegment(account_id) WHERE segment = 'H' Or CREATE INDEX ix_segment_emailsegment ON emailsegment(segment) INCLUDE (account_id) Depending which number of filtered records is smaller created_date >= '1/1/2016' or o.account_id IN ( or o.order_status = 'Shipped' that column has to be the first column within an index. Would say it will be created_date then you have to create an index like: CREATE INDEX ix_created_date_orders on orders(created_date, account_id, order_id) INCLUDE (order_margin) WHERE order_status = 'Shipped'; If your column order_id is a clustered index then you do not have include it into the index. You can try to add word DISTINCT into your sub-query. Not sure if that will help.
Hierarchical parent query in postgres
I am moving from Oracle to Postgresql. I am trying to convert some Oracle hierarchical queries to Postgres. For example, in Oracle to return a comma-delimited ordered list of all ids under (i.e., the children) and including the id_to_start_with I would do the following: SELECT LISTAGG(id_something, ',') WITHIN GROUP (ORDER BY id_something) AS somethings FROM( SELECT DISTINCT D.id_something FROM something_table D START WITH D.id_something = :id_to_start_with CONNECT BY D.id_something_parent = PRIOR D.id_something ) The equivalent in Postgres would seem to be: WITH RECURSIVE the_somethings(id_something) AS ( SELECT id_something FROM something_table WHERE id_something = $id_to_start_with UNION ALL SELECT D.id_something FROM the_somethings DR JOIN something_table D ON DR.id_something = D.id_something_parent ) SELECT string_agg(temp_somethings.id_something::TEXT, ',') AS somethings FROM ( SELECT id_something FROM the_somethings ORDER BY id_something ) AS temp_somethings Likewise if I want to return a comma-delimited ordered list of all ids above (i.e., the parents) and including the id_to_start_with I would do the following in Oracle: SELECT LISTAGG(id_something, ',') WITHIN GROUP (ORDER BY id_something) AS somethings FROM( SELECT DISTINCT D.id_something FROM something_table D START WITH D.id_something = :id_to_start_with CONNECT BY D.id_something = PRIOR D.id_something_parent ) The equivalent in Postgres would seem to be: WITH RECURSIVE the_somethings(id_something, path) AS ( SELECT id_something , id_something::TEXT as path FROM something_table WHERE id_something_parent IS NULL UNION ALL SELECT D.id_something , (DR.path || ',' || D.id_something::TEXT) as path FROM something_table D JOIN the_somethings DR ON DR.id_something = D.id_something_parent ) SELECT path FROM the_somethings WHERE id_something = $id_to_start_with ORDER BY id_something My question has to do with the last Postgres query. It seems terribly inefficient to me and I wonder if there is a better way to write it. That is, in Oracle the query will look for the parent of the id_to_start_with, then the parent of the parent, and so forth to the root. The Postgres query, on the other hand, gets every single root to child path combination possible and then throws everything away except for the one root to id_to_start_with that I am looking for. That is potentially a ton of data to create just to throw it all away except for the one row I am looking for. Is there a way to get a comma-delimited ordered list of all the parents of a particular id_to_start_with that is as performant in Postgres as it is in Oracle? Edit: Adding explain plans from Oracle and Postgres. Oracle Explain Plan Output Postgres Explain Analyyze Output CTE Scan on the_somethings (cost=62.27..74.66 rows=3 width=76) (actual time=0.361..0.572 rows=1 loops=1) Filter: (id_something = 1047) Rows Removed by Filter: 82 CTE the_somethings -> Recursive Union (cost=0.00..62.27 rows=551 width=76) (actual time=0.026..0.433 rows=83 loops=1) -> Seq Scan on something_table (cost=0.00..2.83 rows=1 width=8) (actual time=0.023..0.034 rows=1 loops=1) Filter: (id_something_parent IS NULL) Rows Removed by Filter: 82 -> Hash Join (cost=0.33..4.84 rows=55 width=76) (actual time=0.028..0.065 rows=16 loops=5) Hash Cond: (d.id_something_parent = dr.id_something) -> Seq Scan on something_table d (cost=0.00..2.83 rows=83 width=16) (actual time=0.002..0.012 rows=83 loops=5) -> Hash (cost=0.20..0.20 rows=10 width=76) (actual time=0.009..0.009 rows=17 loops=5) Buckets: 1024 Batches: 1 Memory Usage: 10kB -> WorkTable Scan on the_somethings dr (cost=0.00..0.20 rows=10 width=76) (actual time=0.001..0.004 rows=17 loops=5) Planning time: 0.407 ms Execution time: 0.652 ms This is the final query based on Jakub's answer below. WITH RECURSIVE the_somethings(id_something, path, level, orig_id, id_something_parent) AS ( SELECT id_something , id_something::TEXT as path , 0 as level , id_something AS orig_id , id_something_parent FROM something_table WHERE id_something IN (1047, 448) UNION ALL SELECT D.id_something , (D.id_something::TEXT || ',' || DR.path) as path , DR.level + 1 as level , DR.orig_id as orig_id , D.id_something_parent FROM something_table D JOIN the_somethings DR ON D.id_something = DR.id_something_parent ) SELECT DISTINCT ON(orig_id) orig_id, path FROM the_somethings ORDER BY orig_id, level DESC ;
CTEs in PostgreSQL are fenced meaning they will be materialized and only then will the filter from outer query will be applied. To make the query perform correctly build it the other way around and put the filter inside the CTE. WITH RECURSIVE the_somethings(id_something, path) AS ( SELECT id_something , id_something::TEXT as path, 0 as level, id_something AS orig_id FROM something_table WHERE id_something IN ($id_to_start_with,$id_to_start_with2) UNION ALL SELECT D.id_something , (D.id_something::TEXT || ',' || DR.path) as path, DR.level + 1, DR.orig_id FROM something_table D JOIN the_somethings DR ON DR.id_something_parent = D.id_something ) SELECT DISTINCT ON(orig_id) orig_id, path FROM the_somethings ORDER BY orig_id, DR.level DESC
Clustered Index Scan vs Index Seek
Will including more columns in the clustered index for a table increase the chance of turning index scans into index seeks? I'm trying to increase responsiveness with operations involved with a heavily read table. It has 199 columns and currently 65k rows, is it even worth it? Here's the query: SELECT T1.SALESID,T1.SALESNAME,T1.RESERVATION,T1.CUSTACCOUNT,T1.INVOICEACCOUNT,T1.DELIVERYDATE,T1.URL,T1.PURCHORDERFORMNUM,T1.SALESGROUP,T1.FREIGHTSLIPTYPE,T1.DOCUMENTSTATUS,T1.INTERCOMPANYORIGINALSALESID,T1.CURRENCYCODE,T1.PAYMENT,T1.CASHDISC,T1.TAXGROUP,T1.LINEDISC,T1.CUSTGROUP,T1.DISCPERCENT,T1.INTERCOMPANYORIGINALCUSTACCOUNT,T1.PRICEGROUPID,T1.MULTILINEDISC,T1.ENDDISC,T1.CUSTOMERREF,T1.LISTCODE,T1.DLVTERM,T1.DLVMODE,T1.PURCHID,T1.SALESSTATUS,T1.MARKUPGROUP,T1.SALESTYPE,T1.SALESPOOLID,T1.POSTINGPROFILE,T1.TRANSACTIONCODE,T1.INTERCOMPANYAUTOCREATEORDERS,T1.INTERCOMPANYDIRECTDELIVERY,T1.INTERCOMPANYDIRECTDELIVERYORIG,T1.SETTLEVOUCHER,T1.INTERCOMPANYALLOWINDIRECTCREATION,T1.INTERCOMPANYALLOWINDIRECTCREATIONORIG,T1.DELIVERYNAME,T1.ONETIMECUSTOMER,T1.COVSTATUS,T1.COMMISSIONGROUP,T1.PAYMENTSCHED,T1.INTERCOMPANYORIGIN,T1.EMAIL,T1.FREIGHTZONE,T1.RETURNITEMNUM,T1.CASHDISCPERCENT,T1.CONTACTPERSONID,T1.DEADLINE,T1.PROJID,T1.INVENTLOCATIONID,T1.ADDRESSREFTABLEID,T1.VATNUM,T1.PORT,T1.INCLTAX,T1.NUMBERSEQUENCEGROUP,T1.FIXEDEXCHRATE,T1.LANGUAGEID,T1.AUTOSUMMARYMODULETYPE,T1.SALESORIGINID,T1.ESTIMATE,T1.TRANSPORT,T1.PAYMMODE,T1.PAYMSPEC,T1.FIXEDDUEDATE,T1.EXPORTREASON,T1.STATPROCID,T1.INTERCOMPANYCOMPANYID,T1.INTERCOMPANYPURCHID,T1.INTERCOMPANYORDER,T1.DLVREASON,T1.QUOTATIONID,T1.RECEIPTDATEREQUESTED,T1.RECEIPTDATECONFIRMED,T1.SHIPPINGDATEREQUESTED,T1.SHIPPINGDATECONFIRMED,T1.ITEMTAGGING,T1.CASETAGGING,T1.PALLETTAGGING,T1.ADDRESSREFRECID,T1.CUSTINVOICEID,T1.INVENTSITEID,T1.DEFAULTDIMENSION,T1.CREDITCARDCUSTREFID,T1.SHIPCARRIERACCOUNT,T1.SHIPCARRIERID,T1.SHIPCARRIERFUELSURCHARGE,T1.SHIPCARRIERBLINDSHIPMENT,T1.SHIPCARRIERDELIVERYCONTACT,T1.CREDITCARDAPPROVALAMOUNT,T1.CREDITCARDAUTHORIZATION,T1.RETURNDEADLINE,T1.RETURNREPLACEMENTID,T1.RETURNSTATUS,T1.RETURNREASONCODEID,T1.CREDITCARDAUTHORIZATIONERROR,T1.SHIPCARRIERACCOUNTCODE,T1.RETURNREPLACEMENTCREATED,T1.SHIPCARRIERDLVTYPE,T1.DELIVERYDATECONTROLTYPE,T1.SHIPCARRIEREXPEDITEDSHIPMENT,T1.SHIPCARRIERRESIDENTIAL,T1.MATCHINGAGREEMENT,T1.SYSTEMENTRYSOURCE,T1.SYSTEMENTRYCHANGEPOLICY,T1.MANUALENTRYCHANGEPOLICY,T1.DELIVERYPOSTALADDRESS,T1.SHIPCARRIERPOSTALADDRESS,T1.SHIPCARRIERNAME,T1.WORKERSALESTAKER,T1.SOURCEDOCUMENTHEADER,T1.BANKDOCUMENTTYPE,T1.SALESUNITID,T1.SMMSALESAMOUNTTOTAL,T1.SMMCAMPAIGNID,T1.CASHDISCBASEDATE,T1.CASHDISCBASEDAYS,T1.PDSBATCHATTRIBAUTORES,T1.PDSCUSTREBATEGROUPID,T1.PDSREBATEPROGRAMTMAGROUP,T1.WORKERSALESRESPONSIBLE,T1.AA_INITIALCONDITION,T1.AA_MATERIAL,T1.AA_PONUMBER,T1.AA_REFERENCENUMBER,T1.AA_FINALCONDITION,T1.AA_TEMPLATEID,T1.AA_PRIME,T1.AA_CONTAINER,T1.AA_ENTEREDDATE,T1.AA_ENTEREDDATETZID,T1.AA_EXPEDITE,T1.AA_PROMISEDDATE,T1.AA_PROMISEDDATETZID,T1.AA_GROSSWEIGHT,T1.AA_ALLOY,T1.AA_ITAR,T1.AA_EAR,T1.AA_GSI,T1.AA_SOLUTIONTREAT,T1.AA_BASICFORMID,T1.AA_PLANNEDBY,T1.AA_CLASSIFICATION,T1.INVENTPACKINGMATERIALCODE,T1.AA_CSI,T1.AA_QTY,T1.AA_BILLINGADDRESS,T1.AA_PROCESSMASTER,T1.AA_BILLINGNAME,T1.AA_PACKAGING,T1.AA_HIDECERTMEASURE,T1.AA_INVOICEAPPROVED,T1.AA_PROSHIPMEMOPRINTED,T1.AA_CERTIFIEDDATE,T1.TRI_OPSTATUS,T1.MODIFIEDDATETIME,T1.MODIFIEDBY,T1.CREATEDDATETIME,T1.CREATEDBY,T1.RECVERSION,T1.PARTITION,T1.RECID,T2.PERSON,T2.RECVERSION,T2.RECID,T3.LOCATION,T3.ADDRESS,T3.VALIDFROM,T3.VALIDFROMTZID,T3.VALIDTO,T3.VALIDTOTZID,T3.COUNTRYREGIONID,T3.RECVERSION,T3.RECID,T4.ADDRESS,T4.COUNTRYREGIONID,T4.LOCATION,T4.VALIDFROM,T4.VALIDFROMTZID,T4.RECVERSION,T4.RECID,T5.LOCATION,T5.ADDRESS,T5.VALIDFROM,T5.VALIDFROMTZID,T5.RECVERSION,T5.RECID,T6.NAME,T6.RECID,T6.RECVERSION,T6.INSTANCERELATIONTYPE,T6.NAMESEQUENCE,T6.RECVERSION,T6.RECID,T7.DESCRIPTION,T7.LOCATIONID,T7.RECVERSION,T7.RECID,T8.DESCRIPTION,T8.LOCATIONID,T8.RECVERSION,T8.RECID,T1.AA_COMMENTS FROM SALESTABLE T1 LEFT OUTER JOIN HCMWORKER T2 ON ((T2.PARTITION=#P1) AND ((T1.WORKERSALESTAKER=T2.RECID) AND (T1.WORKERSALESTAKER=T2.RECID))) LEFT OUTER JOIN LOGISTICSPOSTALADDRESS T3 ON ((T3.PARTITION=#P2) AND ((T1.DELIVERYPOSTALADDRESS=T3.RECID) AND ((1=#P3 OR (T3.ISPRIVATE=#P4)) OR (T3.PRIVATEFORPARTY=#P5)))) LEFT OUTER JOIN LOGISTICSPOSTALADDRESS T4 ON ((T4.PARTITION=#P6) AND ((T1.SHIPCARRIERPOSTALADDRESS=T4.RECID) AND ((1=#P7 OR (T4.ISPRIVATE=#P8)) OR (T4.PRIVATEFORPARTY=#P9)))) LEFT OUTER JOIN LOGISTICSPOSTALADDRESS T5 ON ((T5.PARTITION=#P10) AND ((T1.AA_BILLINGADDRESS=T5.RECID) AND ((1=#P11 OR (T5.ISPRIVATE=#P12)) OR (T5.PRIVATEFORPARTY=#P13)))) LEFT OUTER JOIN DIRPARTYTABLE T6 ON ((((T6.PARTITION=#P14) AND (T6.INSTANCERELATIONTYPE IN (#P15,#P16,#P17,#P18,#P19,#P20,#P21) )) AND ((T2.PERSON=T6.RECID) AND (T2.PERSON=T6.RECID))) AND (T6.INSTANCERELATIONTYPE IN (2975) )) LEFT OUTER JOIN LOGISTICSLOCATION T7 ON ((T7.PARTITION=#P22) AND (T3.LOCATION=T7.RECID)) LEFT OUTER JOIN LOGISTICSLOCATION T8 ON ((T8.PARTITION=#P23) AND (T5.LOCATION=T8.RECID)) WHERE (((T1.PARTITION=#P24) AND (T1.DATAAREAID=#P25)) AND (( NOT ((T1.RETURNSTATUS=#P26)) AND NOT ((T1.RETURNSTATUS=#P27))) AND (((((((((((((((((((((((((T1.SALESNAME=#P28) AND (T1.SALESID=#P29)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P30)) AND (T3.VALIDFROM=#P31)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION=#P32)) AND (T5.VALIDFROM=#P33)) AND (T6.NAME IS NULL)) AND (T6.NAMESEQUENCE IS NULL)) AND (T7.LOCATIONID=#P34)) AND (T8.LOCATIONID>=#P35)) OR (((((((((((T1.SALESNAME=#P36) AND (T1.SALESID=#P37)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P38)) AND (T3.VALIDFROM=#P39)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION=#P40)) AND (T5.VALIDFROM=#P41)) AND (T6.NAME IS NULL)) AND (T6.NAMESEQUENCE IS NULL)) AND (T7.LOCATIONID>#P42))) OR ((((((((((T1.SALESNAME=#P43) AND (T1.SALESID=#P44)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P45)) AND (T3.VALIDFROM=#P46)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION=#P47)) AND (T5.VALIDFROM=#P48)) AND (T6.NAME IS NULL)) AND NOT ((T6.NAMESEQUENCE IS NULL)))) OR ((((((((((T1.SALESNAME=#P49) AND (T1.SALESID=#P50)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P51)) AND (T3.VALIDFROM=#P52)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION=#P53)) AND (T5.VALIDFROM=#P54)) AND (T6.NAME IS NULL)) AND NOT ((T6.RECID IS NULL)))) OR (((((((((T1.SALESNAME=#P55) AND (T1.SALESID=#P56)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P57)) AND (T3.VALIDFROM=#P58)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION=#P59)) AND (T5.VALIDFROM=#P60)) AND NOT ((T6.NAME IS NULL)))) OR ((((((((T1.SALESNAME=#P61) AND (T1.SALESID=#P62)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P63)) AND (T3.VALIDFROM=#P64)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION=#P65)) AND (T5.VALIDFROM>#P66))) OR (((((((T1.SALESNAME=#P67) AND (T1.SALESID=#P68)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P69)) AND (T3.VALIDFROM=#P70)) AND (T4.LOCATION IS NULL)) AND (T5.LOCATION>#P71))) OR (((((((T1.SALESNAME=#P72) AND (T1.SALESID=#P73)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P74)) AND (T3.VALIDFROM=#P75)) AND (T4.LOCATION IS NULL)) AND NOT ((T4.VALIDFROM IS NULL)))) OR ((((((T1.SALESNAME=#P76) AND (T1.SALESID=#P77)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P78)) AND (T3.VALIDFROM=#P79)) AND NOT ((T4.LOCATION IS NULL)))) OR (((((T1.SALESNAME=#P80) AND (T1.SALESID=#P81)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION=#P82)) AND (T3.VALIDFROM>#P83))) OR ((((T1.SALESNAME=#P84) AND (T1.SALESID=#P85)) AND (T2.PERSON IS NULL)) AND (T3.LOCATION>#P86))) OR (((T1.SALESNAME=#P87) AND (T1.SALESID=#P88)) AND NOT ((T2.PERSON IS NULL)))) OR ((T1.SALESNAME=#P89) AND (T1.SALESID>#P90))) OR (T1.SALESNAME>#P91)))) ORDER BY T1.SALESNAME,T1.SALESID,T2.PERSON,T3.LOCATION,T3.VALIDFROM,T4.LOCATION,T4.VALIDFROM,T5.LOCATION,T5.VALIDFROM,T6.NAME,T6.RECID,T6.NAMESEQUENCE,T7.LOCATIONID,T8.LOCATIONID OPTION(FAST 2)
It is not possible to pick the columns in a Clustered Index. It always includes all columns. In case you meant key columns: There is no "chance" here. It depends on the query whether an index is a good fit or not. Without schema and query nothing can be said. Refer to pretty much any indexing tutorial to answer this yourself.
Will adding more columns to the clustered index key, aka Primary Key, possibly turn Index Scans into Index Seeks? Yes, but query tuning via Primary Key can create other complications. It may be less painful to just add a Non Clustered Index on the columns that you want "seeked". Can you provide the problem query?
sql query slow 3 leftjoins with where clausel
This first query have one and clausle more and slow down from 200ms to 9-13seconds i dont get why its so. If i remove all where clause i get ~200ms just if i add one more and it will be slow. SELECT DISTINCT a.* , p.*, p2.*, p3.* FROM article a LEFT JOIN pro p ON a.id = p.article_id LEFT JOIN pro p2 ON a.id = p2.article_id LEFT JOIN pro p3 ON a.id = p3.article_id WHERE a.is_active = true AND p.name = 'hotel_stars' AND p2.name = 'article_journey_days' AND p3.name = 'article_persons' AND p3.int_value > 0 AND p3.int_value < 7 AND p.int_value > 0 AND p.int_value < 5 Result 319 Datensätze Laufzeit gesamt: 9,602.081 ms SELECT DISTINCT a.* , p.*, p2.*, p3.* FROM article a LEFT JOIN property p ON a.id = p.article_id LEFT JOIN property p2 ON a.id = p2.article_id LEFT JOIN property p3 ON a.id = p3.article_id WHERE a.is_active = true AND p.name = 'hotel_stars' AND p2.name = 'article_property_journey_days' AND p3.name = 'article_property_persons' AND p3.int_value > 0 AND p3.int_value < 7 // AND p.int_value > 0 AND p.int_value < 5 (removed) Result 469 Datensätze Laufzeit gesamt: 278.453 ms Where is the Problem? Thx EDIT EXPLAIN PLAN: HashAggregate (cost=24113.80..24113.81 rows=1 width=3528) -> Nested Loop (cost=0.00..24113.69 rows=1 width=3528) Join Filter: (a.id = p2.article_id) -> Nested Loop (cost=0.00..16889.70 rows=1 width=2488) -> Nested Loop (cost=0.00..16856.58 rows=4 width=2080) Join Filter: (p.article_id = p3.article_id) -> Seq Scan on property p (cost=0.00..8335.87 rows=115 width=1040) Filter: ((int_value > 0) AND (int_value < 5) AND ((name)::text = 'hotel_stars'::text)) -> Materialize (cost=0.00..8336.41 rows=107 width=1040) -> Seq Scan on property p3 (cost=0.00..8335.87 rows=107 width=1040) Filter: ((int_value > 0) AND (int_value < 7) AND ((name)::text = 'article_property_persons'::text)) -> Index Scan using article_pkey on article a (cost=0.00..8.27 rows=1 width=408) Index Cond: (id = p.article_id) Filter: is_active -> Seq Scan on property p2 (cost=0.00..7185.05 rows=3115 width=1040) Filter: ((name)::text = 'article_property_journey_days'::text) 16 Datensätze Laufzeit gesamt: 11.153 ms Changing To SELECT DISTINCT a.* , p.*, p2.*, p3.* FROM article a INNER JOIN pro p ON a.id = p.article_id AND p.name = 'hotel_stars' AND p.int_value > 0 AND p.int_value < 5 INNER JOIN pro p2 ON a.id = p2.article_id AND p2.name = 'article_journey_days' INNER JOIN pro p3 ON a.id = p3.article_id AND p3.name = 'article_persons' AND p3.int_value > 0 AND p3.int_value < 7 WHERE a.is_active = true Result: 319 Datensätze Laufzeit gesamt: 9,315.863 ms HashAggregate (cost=24113.80..24113.81 rows=1 width=3528) -> Nested Loop (cost=0.00..24113.69 rows=1 width=3528) Join Filter: (a.id = p2.article_id) -> Nested Loop (cost=0.00..16889.70 rows=1 width=2488) -> Nested Loop (cost=0.00..16856.58 rows=4 width=2080) Join Filter: (p.article_id = p3.article_id) -> Seq Scan on property p (cost=0.00..8335.87 rows=115 width=1040) Filter: ((int_value > 0) AND (int_value < 5) AND ((name)::text = 'hotel_stars'::text)) -> Materialize (cost=0.00..8336.41 rows=107 width=1040) -> Seq Scan on property p3 (cost=0.00..8335.87 rows=107 width=1040) Filter: ((int_value > 0) AND (int_value < 7) AND ((name)::text = 'article_property_persons'::text)) -> Index Scan using article_pkey on article a (cost=0.00..8.27 rows=1 width=408) Index Cond: (id = p.article_id) Filter: is_active -> Seq Scan on property p2 (cost=0.00..7185.05 rows=3115 width=1040) Filter: ((name)::text = 'article_property_journey_days'::text) 16 Datensätze Laufzeit gesamt: 4.314 ms Similar question :(
Added Index for column p.name and p.article. Result speed improve from 13sec to 180ms.