Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1XGw4Q-0003XD-Ck for pgsql-sql@arkaria.postgresql.org; Mon, 11 Aug 2014 20:19:54 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.80) (envelope-from ) id 1XGw4P-0007qO-S3 for pgsql-sql@arkaria.postgresql.org; Mon, 11 Aug 2014 20:19:53 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.80) (envelope-from ) id 1XGw4O-0007qF-F0 for pgsql-sql@postgresql.org; Mon, 11 Aug 2014 20:19:52 +0000 Received: from post.officenet.no ([195.225.13.103]) by magus.postgresql.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1XGw4J-0004as-FK for pgsql-sql@postgresql.org; Mon, 11 Aug 2014 20:19:51 +0000 Received: from [10.47.1.10] (helo=tc7-on) by post.officenet.no with esmtp (Exim 4.76) (envelope-from ) id 1XGw4F-000GdV-N4 for pgsql-sql@postgresql.org; Mon, 11 Aug 2014 22:19:47 +0200 Received: from localhost ([127.0.0.1] helo=tc7-on) by tc7-on with esmtp (Exim 4.76) (envelope-from ) id 1XGw3Y-0004k5-PL for pgsql-sql@postgresql.org; Mon, 11 Aug 2014 22:19:00 +0200 Date: Mon, 11 Aug 2014 22:19:00 +0200 (CEST) From: Andreas Joseph Krogh To: pgsql-sql@postgresql.org Message-ID: In-Reply-To: Subject: Re: How to optimize WHERE column_a IS NOT NULL OR column_b = 'value' MIME-Version: 1.0 X-Mailer: Visena Mail 1.9.0-SNAPSHOT X-Spam-Score: -1.0 X-Spam-Report: SpamAssasin (score=-1.0, required 5.0 ALL_TRUSTED=-1, HTML_MESSAGE=0.001) X-Pg-Spam-Score: -1.9 (-) Content-Type: multipart/related; boundary="----=_Part_91_964186347.1407788340647" List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-sql Precedence: bulk Sender: pgsql-sql-owner@postgresql.org ------=_Part_90_412636930.1407788340647 Content-Type: multipart/related; boundary="----=_Part_91_964186347.1407788340647" ------=_Part_91_964186347.1407788340647 Content-Type: multipart/alternative; boundary="----=_Part_92_863090014.1407788340667" ------=_Part_92_863090014.1407788340667 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable P=C3=A5 mandag 11. august 2014 kl. 21:34:57, skrev Pavel Stehule < pavel.stehule@gmail.com >: Hi =C2=A0 2014-0= 8-11=20 18:01 GMT+02:00 Andreas Joseph Krogh>: Hi folks, =C2=A0 I have the following schema= =20 (simplified for this example). =C2=A0 create table folder(id integer primar= y key,=20 name varchar not null); =C2=A0 create table document(id serial primary key,= name=20 varchar not null, owner_id integer not null, folder_id integer references= =20 folder(id)); create index document_owner_idx ON document(owner_id); create= =20 index document_folder_idx ON document(folder_id); =C2=A0 insert into folder= (id,=20 name) values(1, 'Folder A'); insert into folder(id, name) values(2, 'Folder= B'); insert into document(name, owner_id, folder_id) values('Document A',=C2=A0 = 1, 1);=20 insert into document(name, owner_id, folder_id) values('Document B',=C2=A0 = 1, NULL);=20 insert into document(name, owner_id, folder_id) values('Document C',=C2=A0 = 2, 2);=20 insert into document(name, owner_id, folder_id) values('Document D',=C2=A0 = 2, NULL);=20 =C2=A0 select f.id , f.name , doc.id ,=20 doc.owner_id,doc.name FROM document doc left outer join= =20 folder f ON doc.folder_id =3Df.id WHERE doc.folder_id is not = null=20 OR doc.owner_id =3D 1; =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=20 QUERY PLAN =20 ---------------------------------------------------------------------------= -------------------------------------------------- =C2=A0Nested Loop Left Join=C2=A0 (cost=3D0.15..13.77 rows=3D4 width=3D76)= (actual=20 time=3D0.031..0.045 rows=3D3 loops=3D1) =C2=A0=C2=A0 ->=C2=A0 Seq Scan on document doc=C2=A0 (cost=3D0.00..1.05 ro= ws=3D4 width=3D44) (actual=20 time=3D0.012..0.018 rows=3D3 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NO= T NULL) OR (owner_id =3D 1)) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Rows Removed by Filter: 1 =C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (cost= =3D0.15..3.17 rows=3D1=20 width=3D36) (actual time=3D0.005..0.006 rows=3D1 loops=3D3) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (doc.folder_i= d =3D id) =C2=A0Planning time: 0.267 ms =C2=A0Execution time: 0.094 ms (8 rows) =C2=A0 =C2=A0 Is the a way to write a query which uses an index e= fficiently=20 for such a schema? =C2=A0 I'd like to eliminate the Filter: ((folder_id IS = NOT NULL)=20 OR (owner_id =3D 1)) and rather have "index cond" insted, is that possible?= =C2=A0=20 your example is partially broken - ANALYZE and hashjoin and seqscan=20 penalization are missing - index scan is not used due too small table sizes =C2=A0 I tested 9.5, probably same as 9.4 and there indexes are used postgres=3D# set enable_hashjoin to off; SET Time: 0.473 ms postgres=3D# set enable_seqscan to off; SET Time: 0.904 ms postgres=3D# explain select f.id , f.name , do= c.id=20 , doc.owner_id, doc.name FROM document doc left outer join folder f ON doc.folder_id =3D f.id=20 WHERE doc.folder_id is not null OR doc.owner_id =3D 1; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 QUERY=20 PLAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =20 =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =C2=A0Merge Left Join=C2=A0 (cost=3D0.26..24.38 rows=3D3 width=3D32) =C2=A0=C2=A0 Merge Cond: (doc.folder_id =3D f.id ) =C2=A0=C2=A0 ->=C2=A0 Index Scan using document_folder_idx on document doc= =C2=A0=20 (cost=3D0.13..12.20 rows=3D3 width=3D23) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NO= T NULL) OR (owner_id =3D 1)) =C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (cost= =3D0.13..12.16 rows=3D2=20 width=3D13) =C2=A0Planning time: 0.663 ms (6 rows) =C2=A0 default 9.2, 9.3, ... postgres=3D# explain select f.id , f.name , do= c.id=20 , doc.owner_id, doc.name FROM document doc left outer join folder f ON doc.folder_id =3D f.id=20 WHERE doc.folder_id is not null OR doc.owner_id =3D 1; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 QUERY PLAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80 =C2=A0Hash Left Join=C2=A0 (cost=3D1.04..2.12 rows=3D3 width=3D32) =C2=A0=C2=A0 Hash Cond: (doc.folder_id =3D f.id ) =C2=A0=C2=A0 ->=C2=A0 Seq Scan on document doc=C2=A0 (cost=3D0.00..1.05 ro= ws=3D3 width=3D23) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NO= T NULL) OR (owner_id =3D 1)) =C2=A0=C2=A0 ->=C2=A0 Hash=C2=A0 (cost=3D1.02..1.02 rows=3D2 width=3D13) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ->=C2=A0 Seq Scan on fold= er f=C2=A0 (cost=3D0.00..1.02 rows=3D2 width=3D13) (6 rows) =C2=A0 and 9.2 after hashjoin and indexscan penalization postgres=3D# explain select f.id , f.name , do= c.id=20 , doc.owner_id, doc.name FROM document doc left outer join folder f ON doc.folder_id =3D f.id=20 WHERE doc.folder_id is not null OR doc.owner_id =3D 1; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 QUERY=20 PLAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =20 =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =C2=A0Merge Left Join=C2=A0 (cost=3D0.00..24.62 rows=3D3 width=3D32) =C2=A0=C2=A0 Merge Cond: (doc.folder_id =3D f.id ) =C2=A0=C2=A0 ->=C2=A0 Index Scan using document_folder_idx on document doc= =C2=A0=20 (cost=3D0.00..12.32 rows=3D3 width=3D23) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NO= T NULL) OR (owner_id =3D 1)) =C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (cost= =3D0.00..12.28 rows=3D2=20 width=3D13) (5 rows) Time: 2.258 ms =C2=A0 What is your PostgreSQL? =C2=A0 Regards =C2=A0 Pavel =C2=A0 P.S. ten years ago I had a similar issue - "OR" predikates can be r= eplaced=20 by UNION =C2=A0 you can try: =C2=A0 SELECT * FROM (SELECT * FROM doc =C2=A0 WHERE folder_id IS NOT NULL UNION =C2=A0 SELECT * FROM doc =C2=A0 W= HERE owner_id =3D 1)=20 s =C2=A0 LEFT JOIN folder ON s.folder_id =3D folder.id =C2=A0 or some similar magic =C2=A0 select f.id , f.name ,=20 doc.id , doc.owner_id, doc.name FROM docum= ent=20 doc left outer join folder f ON doc.folder_id =3Df.id WHERE= =20 doc.folder_id is not null OR doc.owner_id =3D 1; =C2=A0 I see turning enabl= e_seqscan=20 to off results in BitmapOr in 9.3: =C2=A0 loff=3D# select version(); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=20 version=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 =C2=A0 =20 ---------------------------------------------------------------------------= ---------------------------------- =C2=A0PostgreSQL 9.3.2 on x86_64-unknown-linux-gnu, compiled by gcc (Ubunt= u/Linaro=20 4.8.1-10ubuntu9) 4.8.1, 64-bit (1 row) loff=3D# show enable_seqscan ; =C2=A0enable_seqscan ---------------- =C2=A0off (1 row) loff=3D# explain analyze=C2=A0 select f.id, f.name, doc.id, doc.ow= ner_id,=20 doc.name FROM document doc left outer join folder f ON doc.folder_id =3D f.id WHERE doc.folder_id is not null OR doc.owner_id =3D 1; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 QUERY PLAN =20 ---------------------------------------------------------------------------= ----------------------------------------------------------------- =C2=A0Hash Left Join=C2=A0 (cost=3D103.08..141.89 rows=3D1095 width=3D76) = (actual=20 time=3D0.052..0.057 rows=3D3 loops=3D1) =C2=A0=C2=A0 Hash Cond: (doc.folder_id =3D f.id) =C2=A0=C2=A0 ->=C2=A0 Bitmap Heap Scan on document doc=C2=A0 (cost=3D21.10= ..44.85 rows=3D1095=20 width=3D44) (actual time=3D0.027..0.028 rows=3D3 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Recheck Cond: ((folder_id= IS NOT NULL) OR (owner_id =3D 1)) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ->=C2=A0 BitmapOr=C2=A0 (= cost=3D21.10..21.10 rows=3D1100 width=3D0) (actual=20 time=3D0.018..0.018 rows=3D0 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 ->=C2=A0 Bitmap Index Scan on document_folder_idx=C2=A0=20 (cost=3D0.00..16.36 rows=3D1094 width=3D0) (actual time=3D0.012..0.012 rows= =3D2 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (folder_id IS = NOT NULL) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 ->=C2=A0 Bitmap Index Scan on document_owner_idx=C2=A0 (cost= =3D0.00..4.20=20 rows=3D6 width=3D0) (actual time=3D0.005..0.005 rows=3D2 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (owner_id =3D = 1) =C2=A0=C2=A0 ->=C2=A0 Hash=C2=A0 (cost=3D66.60..66.60 rows=3D1230 width=3D= 36) (actual time=3D0.011..0.011=20 rows=3D2 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Buckets: 1024=C2=A0 Batch= es: 1=C2=A0 Memory Usage: 1kB =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ->=C2=A0 Index Scan using= folder_pkey on folder f=C2=A0 (cost=3D0.15..66.60=20 rows=3D1230 width=3D36) (actual time=3D0.005..0.006 rows=3D2 loops=3D1) =C2=A0Total runtime: 0.125 ms (13 rows) =C2=A0 =C2=A0 =C2=A0 In 9.4-beta2 it results in an index-scan wi= th a filter: =C2=A0=20 andreak=3D# select version(); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 version =20 ---------------------------------------------------------------------------= ------------------------------ =C2=A0PostgreSQL 9.4beta2 on x86_64-unknown-linux-gnu, compiled by gcc (Ub= untu=20 4.8.2-19ubuntu1) 4.8.2, 64-bit (1 row) andreak=3D# show enable_seqscan ; =C2=A0enable_seqscan ---------------- =C2=A0off (1 row) andreak=3D# explain analyze select f.id, f.name, doc.id, doc.owner= _id,=20 doc.name FROM document doc left outer join folder f ON doc.folder_id =3D f.id WHERE doc.folder_id is not null OR doc.owner_id =3D 1; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= QUERY PLAN =20 ---------------------------------------------------------------------------= -------------------------------------------------------------- =C2=A0Nested Loop Left Join=C2=A0 (cost=3D0.28..18.92 rows=3D4 width=3D76)= (actual=20 time=3D0.032..0.044 rows=3D3 loops=3D1) =C2=A0=C2=A0 ->=C2=A0 Index Scan using document_folder_idx on document doc= =C2=A0 (cost=3D0.13..6.20=20 rows=3D4 width=3D44) (actual time=3D0.018..0.024 rows=3D3 loops=3D1) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NO= T NULL) OR (owner_id =3D 1)) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Rows Removed by Filter: 1 =C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (cost= =3D0.15..3.17 rows=3D1=20 width=3D36) (actual time=3D0.003..0.004 rows=3D1 loops=3D3) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (doc.folder_i= d =3D id) =C2=A0Planning time: 0.260 ms =C2=A0Execution time: 0.094 ms (8 rows) =C2=A0 =C2=A0 I have quite large dataset (and some additional joi= ns) in my=20 prod-data and hoped that I could solve this with one index-scan on an index= on=20 document-table to avoid 2 index-scans and OR-ing the results. =C2=A0 Thanks= for help! =C2=A0 -- Andreas Joseph Krogh CTO / Partner - Visena AS Mobile: +47 909 56= 963=20 andreas@visena.com www.visena.com=20 =C2=A0 ------=_Part_92_863090014.1407788340667 Content-Type: text/html;charset=UTF-8 Content-Transfer-Encoding: quoted-printable
P=C3=A5 mandag 11. august 2014 kl. 21:34:57, skrev Pavel Stehule <<= a href=3D"mailto:pavel.stehule@gmail.com">pavel.stehule@gmail.com>:<= /div>
Hi
=C2=A0
2014-08-11 18:01 GMT+02:00 Andreas Joseph Krogh = <andreas@visena.com>:
Hi folks,
=C2=A0
I have the following schema (simplified for this example).
=C2=A0
create table folder(id integer primary key, name varchar not null);
=C2=A0
create table document(id serial primary key, name varchar not null, ow= ner_id integer not null, folder_id integer references folder(id));
create index document_owner_idx ON document(owner_id);
create index document_folder_idx ON document(folder_id);
=C2=A0
insert into folder(id, name) values(1, 'Folder A');
insert into folder(id, name) values(2, 'Folder B');
insert into document(name, owner_id, folder_id) values('Document A',= =C2=A0 1, 1);
insert into document(name, owner_id, folder_id) values('Document B',= =C2=A0 1, NULL);
insert into document(name, owner_id, folder_id) values('Document C',= =C2=A0 2, 2);
insert into document(name, owner_id, folder_id) values('Document D',= =C2=A0 2, NULL);
=C2=A0
select f.id, f.name, doc.id, doc.owner_id, doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 QUERY PLAN
---------------------------------------------------------------------------= --------------------------------------------------
=C2=A0Nested Loop Left Join=C2=A0 (cost=3D0.15..13.77 rows=3D4 width=3D76) = (actual time=3D0.031..0.045 rows=3D3 loops=3D1)
=C2=A0=C2=A0 ->=C2=A0 Seq Scan on document doc=C2=A0 (cost=3D0.00..1.05 = rows=3D4 width=3D44) (actual time=3D0.012..0.018 rows=3D3 loops=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NOT= NULL) OR (owner_id =3D 1))
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Rows Removed by Filter: 1<= br> =C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (co= st=3D0.15..3.17 rows=3D1 width=3D36) (actual time=3D0.005..0.006 rows=3D1 l= oops=3D3)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (doc.folder_id= =3D id)
=C2=A0Planning time: 0.267 ms
=C2=A0Execution time: 0.094 ms
(8 rows)
=C2=A0
=C2=A0
Is the a way to write a query which uses an index efficiently for such= a schema?
=C2=A0
I'd like to eliminate the Filter: ((folder_id IS NOT NULL) OR (owner_i= d =3D 1)) and rather have "index cond" insted, is that possible?<= /div>
=C2=A0
your example is partially broken - ANALYZE and hashjoin and seqscan pe= nalization are missing - index scan is not used due too small table sizes =C2=A0
I tested 9.5, probably same as 9.4 and there indexes are used

postgres=3D# set enable_hashjoin to off;
SET
Time: 0.473 ms
postgres=3D# set enable_seqscan to off;
SET
Time: 0.904 ms
postgres=3D# explain select f.id, f.name, doc.id, doc.owner_id= , doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 QUERY PLAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80
=C2=A0Merge Left Join=C2=A0 (cost=3D0.26..24.38 rows=3D3 width=3D32)
=C2=A0=C2=A0 Merge Cond: (doc.folder_id =3D f.id)
=C2=A0=C2=A0 ->=C2=A0 Index Scan using document_folder_idx on document d= oc=C2=A0 (cost=3D0.13..12.20 rows=3D3 width=3D23)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NOT= NULL) OR (owner_id =3D 1))
=C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (co= st=3D0.13..12.16 rows=3D2 width=3D13)
=C2=A0Planning time: 0.663 ms
(6 rows)
=C2=A0
default 9.2, 9.3, ...

postgres=3D# explain select
f.id, f.name, doc.id, doc.owner_id= , doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 QUERY PLAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80
=C2=A0Hash Left Join=C2=A0 (cost=3D1.04..2.12 rows=3D3 width=3D32)
=C2=A0=C2=A0 Hash Cond: (doc.folder_id =3D f.id= )
=C2=A0=C2=A0 ->=C2=A0 Seq Scan on document doc=C2=A0 (cost=3D0.00..1.05 = rows=3D3 width=3D23)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NOT= NULL) OR (owner_id =3D 1))
=C2=A0=C2=A0 ->=C2=A0 Hash=C2=A0 (cost=3D1.02..1.02 rows=3D2 width=3D13)=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ->=C2=A0 Seq Scan on fo= lder f=C2=A0 (cost=3D0.00..1.02 rows=3D2 width=3D13)
(6 rows)
=C2=A0
and 9.2 after hashjoin and indexscan penalization

postgres=3D# explain select f.id, f.name, doc.id, doc.owner_id= , doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 QUERY PLAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80
=C2=A0Merge Left Join=C2=A0 (cost=3D0.00..24.62 rows=3D3 width=3D32)
=C2=A0=C2=A0 Merge Cond: (doc.folder_id =3D f.id)
=C2=A0=C2=A0 ->=C2=A0 Index Scan using document_folder_idx on document d= oc=C2=A0 (cost=3D0.00..12.32 rows=3D3 width=3D23)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NOT= NULL) OR (owner_id =3D 1))
=C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (co= st=3D0.00..12.28 rows=3D2 width=3D13)
(5 rows)

Time: 2.258 ms
=C2=A0
What is your PostgreSQL?
=C2=A0
Regards
=C2=A0
Pavel
=C2=A0
P.S. ten years ago I had a similar issue - "OR" predikates c= an be replaced by UNION
=C2=A0
you can try:
=C2=A0
SELECT * FROM
(SELECT * FROM doc
=C2=A0 WHERE folder_id IS NOT NULL
UNION
=C2=A0 SELECT * FROM doc
=C2=A0 WHERE owner_id =3D 1) s
or some similar magic
=C2=A0
select f.id, f.name, doc.id, doc.owner_id, doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0
I see turning enable_seqscan to off results in BitmapOr in 9.3:
=C2=A0
loff=3D# select version();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= version=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 =C2=A0
---------------------------------------------------------------------------= ----------------------------------
=C2=A0PostgreSQL 9.3.2 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu= /Linaro 4.8.1-10ubuntu9) 4.8.1, 64-bit
(1 row)
loff=3D# show enable_seqscan ;
=C2=A0enable_seqscan
----------------
=C2=A0off
(1 row)
loff=3D# explain analyze=C2=A0 select f.id, f.name, doc.id, doc.owner_= id, doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 QUERY PLAN
---------------------------------------------------------------------------= -----------------------------------------------------------------
=C2=A0Hash Left Join=C2=A0 (cost=3D103.08..141.89 rows=3D1095 width=3D76) (= actual time=3D0.052..0.057 rows=3D3 loops=3D1)
=C2=A0=C2=A0 Hash Cond: (doc.folder_id =3D f.id)
=C2=A0=C2=A0 ->=C2=A0 Bitmap Heap Scan on document doc=C2=A0 (cost=3D21.= 10..44.85 rows=3D1095 width=3D44) (actual time=3D0.027..0.028 rows=3D3 loop= s=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Recheck Cond: ((folder_id = IS NOT NULL) OR (owner_id =3D 1))
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ->=C2=A0 BitmapOr=C2=A0= (cost=3D21.10..21.10 rows=3D1100 width=3D0) (actual time=3D0.018..0.018 ro= ws=3D0 loops=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ->=C2=A0 Bitmap Index Scan on document_folder_idx=C2=A0 (cost= =3D0.00..16.36 rows=3D1094 width=3D0) (actual time=3D0.012..0.012 rows=3D2 = loops=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (folder_id IS NOT= NULL)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 ->=C2=A0 Bitmap Index Scan on document_owner_idx=C2=A0 (cost= =3D0.00..4.20 rows=3D6 width=3D0) (actual time=3D0.005..0.005 rows=3D2 loop= s=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (owner_id =3D 1)<= br> =C2=A0=C2=A0 ->=C2=A0 Hash=C2=A0 (cost=3D66.60..66.60 rows=3D1230 width= =3D36) (actual time=3D0.011..0.011 rows=3D2 loops=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Buckets: 1024=C2=A0 Batche= s: 1=C2=A0 Memory Usage: 1kB
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ->=C2=A0 Index Scan usi= ng folder_pkey on folder f=C2=A0 (cost=3D0.15..66.60 rows=3D1230 width=3D36= ) (actual time=3D0.005..0.006 rows=3D2 loops=3D1)
=C2=A0Total runtime: 0.125 ms
(13 rows)
=C2=A0
=C2=A0
=C2=A0
In 9.4-beta2 it results in an index-scan with a filter:
=C2=A0
andreak=3D# select version();
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 version
---------------------------------------------------------------------------= ------------------------------
=C2=A0PostgreSQL 9.4beta2 on x86_64-unknown-linux-gnu, compiled by gcc (Ubu= ntu 4.8.2-19ubuntu1) 4.8.2, 64-bit
(1 row)
andreak=3D# show enable_seqscan ;
=C2=A0enable_seqscan
----------------
=C2=A0off
(1 row)
andreak=3D# explain analyze select f.id, f.name, doc.id, doc.owner_id,= doc.name
FROM document doc left outer join folder f ON doc.folder_id =3D f.id
WHERE doc.folder_id is not null OR doc.owner_id =3D 1;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 QU= ERY PLAN
---------------------------------------------------------------------------= --------------------------------------------------------------
=C2=A0Nested Loop Left Join=C2=A0 (cost=3D0.28..18.92 rows=3D4 width=3D76) = (actual time=3D0.032..0.044 rows=3D3 loops=3D1)
=C2=A0=C2=A0 ->=C2=A0 Index Scan using document_folder_idx on document d= oc=C2=A0 (cost=3D0.13..6.20 rows=3D4 width=3D44) (actual time=3D0.018..0.02= 4 rows=3D3 loops=3D1)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Filter: ((folder_id IS NOT= NULL) OR (owner_id =3D 1))
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Rows Removed by Filter: 1<= br> =C2=A0=C2=A0 ->=C2=A0 Index Scan using folder_pkey on folder f=C2=A0 (co= st=3D0.15..3.17 rows=3D1 width=3D36) (actual time=3D0.003..0.004 rows=3D1 l= oops=3D3)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index Cond: (doc.folder_id= =3D id)
=C2=A0Planning time: 0.260 ms
=C2=A0Execution time: 0.094 ms
(8 rows)
=C2=A0
=C2=A0
I have quite large dataset (and some additional joins) in my prod-data= and hoped that I could solve this with one index-scan on an index on docum= ent-table to avoid 2 index-scans and OR-ing the results.
=C2=A0
Thanks for help!
=C2=A0
--
Andrea= s Joseph Krogh
CTO / Partner<= /span> - Visena AS
Mobile: +47 90= 9 56 963
=3D""
=C2=A0
------=_Part_92_863090014.1407788340667-- ------=_Part_91_964186347.1407788340647 Content-Type: image/png Content-Transfer-Encoding: base64 Content-Disposition: inline Content-ID: iVBORw0KGgoAAAANSUhEUgAAAIUAAAAYCAYAAADUIj6hAAAABHNCSVQICAgIfAhkiAAABzBJREFU aEPtmNFxHDcMhmVP3i1VECpvnjzkVIHWFfhcgVcVRKrAUgWRK/C6Al8H3lTgy0PGbzFdQc4VJP/H ADs43q6kROeJNbOYgQACIAgCWJKng4MZ5gxUGXh0U0b+SIuF9G+EWXj2Q15vbrE/NPtk9uub7Gfd t5mBx1NhqSEo8HshjbEUtlO2yIM9tsx5dZP9rPt2MzDZFAqZE4LGcFjdsg3saQaHt7fY70X949On aS+OZidDBkavD33157L4xaw2os+Mp/DAC10l2XhOCeStj0W5ajrJL8WfCi80Xgf9vVlrhg9yRONe /f7xI2vNsIcM7JwU9o6oGyJrLT8JOA1aX9sKP4wl94bAniukEbo/n7YPmuTETzIab4Y9ZWCrKexd 8M58lxPCvvD6aihfvexbEQoPYO8NQRO0JnddGO6FJYaVsBde7cXj7KRk4LsqDxQzCYeGsJNgaXZe +JXkyGgWINq3Gp+bHNILz+wEYs5qH1eJrouNrpDXtk4O6x1IvtD40GWyJYYdkF0jIbYZlN16xygI gl9smbMDsmFdfAKb23xGB8H/mv3tOJfArs1kukk79DEPdQ5u0g1vCvvqKXIW8mZYW+F3Tg4r8HvZ kQCCLydK8EFMQCe5N8RgL9mRG0SqQFuNvdE6beSs0qPDBuCdg0+gvClso8SbTO4ki7mQzQqBrcMH QPwReg2wW8umEe/+L8T/LEzBGF9nXjzZ46s+ITHvhegW8LL39xm6App7KYL/GE+vcYnFbJiP/0aY hdiCnRC7jaj7eiK2ETInC5PRF6LYkSN0+HabF75WuT6syCyI0YkVGGMvUC33AmfZTDUEj8u6IVhu EhRUJ2U2g6UlugyNb03Hl9obHwlxJbcRzcYjO4QPjVfGFTQav4vrmp7cpMp2qbHnBxWJbisbho2Q XI6C1sIHDUFhH4Hij4UbIev66eANeiwbkA+LBsO36zAHzoXU7AhbqLAXEiOYTXcSdO8VS9L4wN8U BIYhBd6oSUgYMijOkecRuTdQa/YiBXhbXFcnCnI2SrfeBG9NydrLYMhGHa5qB9pQIxlzAE6Okjzx JO5afGe6kmhBicWKQNKuTZ5EW+MjQY8v/9rQ0bhJSJyNGUe/JH1t8h1iMbdSPAvxHYin6YmN9YBX QmTYZZNh14vHhhhal5vtcIrJjmvszPRJdExH3MWHvykoBEc9CoCGWJisOLOGoCORs1FvIMbYA8z3 kwM59oemy6LlWrLxFLmWgiQAfEGd8S+NssbK+EhyGLxUkhhiy717waBqHOJYSEacwBejkFNhjJNj v/gANOdQxPfciP/JVBCK2cOIcg3RRJ+CPrLPNVhhN6F38VKMF3XLlIJrjU5C8gMFxvKDvOcPc4rV NjCn7KM0BV+161V8viSCuJZ8SITGJGEh7IUUlxOFMYUH1kJOCN4Wh+I5pqCuK01k40kSNtnKiKIl UfxAgW5sU5JlS05rtt5YFJF1SWoqHv6BRgQcA4/bdb9WRjmMk3jyUMAbIoyJq9e4cVmgzKt9j5gN J/aYDhk+hhjExwaPcz5PObA5Zd9bvz5UzCTZuZDidu5AchpiKSwPR+TV1bCWqBQ9nCjJ5neivC82 Nr4LeS2j1gw5LUqwBuhGQQU5UwHeSslXkwIynz2U2A2yKDgG7OffwLA3TpGRpk0Tzpj3ZEJXi/GR a6GN0e0NtppChePdcAz1FTS+FN8Kpxoiykk+J8fC5tenjbu9kSqpHLu9jBrhUuhNwVGbpyZrzrl0 HPVD8SXj5EOOD/eDC64VjvYBZLuUbIVAfBN1t/C/SU+cAGtdGo+fVnzycUX5wmn6eCKPmWYJG2E/ ppTsuRCbvUD9fwquksG5GqLVKhzDQ3GrEyLKSXhsiK3T5j9EyxffCFOYi2wUlPyFFDQAhehESDjQ GoX0ho0oj8RPou6TxHJdcT0NTcWkO0AnG7+uXsnHqcas/72wvWF+mSf7N/Watp9kTXoluzeS0fB9 9CcZ/hvhSZTfh99pispZOXL9KrGrARkNUMu9ITbScZWs7xOYNt9pwxSZtYDsX/GE3xTkrXgwAsXm fud08FiTeC+m2/o7ppo+PTS/NBK5ARpDG5YHr++DpmVfreYdiX8mnp+DzPEG9WbqJON0JBenZofs sxBA1gj5NXGvfJu/Qh7HwQh/VDUEyUxCit5hH94QfKkEdu+GwK8BX0hvCF+D67xhjmXQCXMwJCZ+ olK0A1EKRCE4snsh42w8Mv/Zhxw9iD7Cjo7CyQC/KyF6oBfShL4PYgG+CHsYKyZxvxZSZBAgjhIz YDz+AbfD37GtbaoSKzgGt+lKfI/GZtay6vG4VXTpPsh+IcQhOk9I7WYeP5AM3HZ9+DaSGIp9HIuu huC4pCGGx+YD2fcc5tfIAA0h/Et4/jX8zz4fWAasIf4UbR9Y6HO4d8jAnd4U0Y8ageuCB+c+H5R3 CHU2mTMwZ+B/y8DfSMBLLOYXVuEAAAAASUVORK5CYII= ------=_Part_91_964186347.1407788340647-- ------=_Part_90_412636930.1407788340647--