Re: Bad query plan when you add many OR conditions
Marco Colli <[email protected]> Fri, 10 Jan 2020 15:53:22 +0100
| Newsgroups | gmane.comp.db.postgresql.performance |
|---|---|
| Message-ID | <CAFvCgN7yQFLjwLSs7VPLp8VxUrGTy5uzmQ8_GfraXTUSQdyoQQ@mail.gmail.com> |
--0000000000002aadbc059bca4ab7 Content-Type: text/plain; charset="UTF-8" Before trying other solutions I would like to make PG use an index-only scan (it should be fast enough for our purpose). I have tried to disable the other indexes and forced PG to use this index (which includes all the fields of the query): index_subscriptions_on_project_id_and_created_at_and_tags The problem is that the query plan is this: https://gist.github.com/collimarco/03f3dde372f001485518b8deca2f3b24#file-index_scan_instead_of_index_only-txt As you can see it is a *index scan* and not an *index only* scan... I don't understand why. The index includes all the fields used by the query... so an index only scan should be possible. On Fri, Jan 10, 2020 at 2:34 PM Justin Pryzby <[email protected]> wrote: > On Fri, Jan 10, 2020 at 12:03:39PM +0100, Marco Colli wrote: > > I have added this index which would allow an index only scan: > > "index_subscriptions_on_project_id_and_created_at_and_tags" btree > > (project_id, created_at DESC, tags) WHERE trashed_at IS NULL > > Are those the only columns in subscriptions ? > > > But Postgresql continues to use this index (which has less information > and > > then requires slow access to disk): > > "index_subscriptions_on_project_id_and_created_at" btree (project_id, > > created_at DESC) > > Did you vacuum the table ? > Did you try to "explain" the query after dropping the 1st index (like: > begin; > DROP INDEX..; explain analyze..; rollback). > > Also, is the first (other) index btree_gin (you can \dx to show > extensions) ? > > I think it needs to be a gin index to search tags ? > > On Fri, Jan 10, 2020 at 01:42:24PM +0100, Marco Colli wrote: > > I would like to try your solution but I read that ALTER TABLE... SET > > STATISTICS locks the table... Since it is just an experiment and we > don't > > know if it actually works it would be greate to avoid locking a large > table > > (50M) in production. > > I suggest to CREATE TABLE test_subscriptions (LIKE subscriptions INCLUDING > ALL); INSERT INTO test_subscriptions SELECT * FROM subscriptions; ANALYZE > test_subscriptions; > > Anyway, ALTER..SET STATS requires a strong lock but for only a brief moment > (assuming it doesn't have to wait). Possibly you'd be ok doing SET > statement_timeout='1s'; ALTER TABLE.... > > > Does CREATE STATISTICS lock the table too? > > You can check by SET client_min_messages=debug; SET lock_timeout=333; SET > log_lock_waits=on; > Looks like it needs ShareUpdateExclusiveLock. > > > Does statistics work on an array field like tags? (I can't find any > > information) > > It think it'd be data type agnostic. And seems to work with arrays. > > On Fri, Jan 10, 2020 at 02:30:27PM +0100, Marco Colli wrote: > > @Justin Pryzby I have tried this as you suggested: > > > > CREATE STATISTICS statistics_on_subscriptions_project_id_and_tags ON > > project_id, tags FROM subscriptions; > > VACUUM ANALYZE subscriptions; > > > > Unfortunately nothing changes and Postgresql continues to use the wrong > > plan (maybe stats don't work well on array fields like tags??). > > It'd help to see SELECT stxddependencies FROM pg_statistic_ext WHERE > stxoid='subscriptions'::regclass > --0000000000002aadbc059bca4ab7 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div dir=3D"ltr"><div>Before trying other solutions I woul= d like to make PG use an index-only scan (it should be fast enough for our = purpose).</div><div dir=3D"ltr"><br></div><div dir=3D"ltr">I have tried to = disable the other indexes and forced PG to use this index (which includes a= ll the fields of the query):<div>index_subscriptions_on_project_id_and_crea= ted_at_and_tags<br></div><div><br></div><div>The problem is that the query = plan is this:</div><div><a href=3D"https://gist.github.com/collimarco/03f3d= de372f001485518b8deca2f3b24#file-index_scan_instead_of_index_only-txt">http= s://gist.github.com/collimarco/03f3dde372f001485518b8deca2f3b24#file-index_= scan_instead_of_index_only-txt</a><br></div><div><br></div><div>As you can = see it is a *index scan* and not an *index only* scan... I don't unders= tand why. The index includes all the fields used by the query... so an inde= x only scan should be possible.</div><div><br></div></div></div></div><br><= div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Fri, Jan= 10, 2020 at 2:34 PM Justin Pryzby <<a href=3D"mailto:[email protected]= om">[email protected]</a>> wrote:<br></div><blockquote class=3D"gmail= _quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left= -style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">On Fri, J= an 10, 2020 at 12:03:39PM +0100, Marco Colli wrote:<br> > I have added this index which would allow an index only scan:<br> > "index_subscriptions_on_project_id_and_created_at_and_tags" = btree<br> > (project_id, created_at DESC, tags) WHERE trashed_at IS NULL<br> <br> Are those the only columns in subscriptions ?<br> <br> > But Postgresql continues to use this index (which has less information= and<br> > then requires slow access to disk):<br> > "index_subscriptions_on_project_id_and_created_at" btree (pr= oject_id,<br> > created_at DESC)<br> <br> Did you vacuum the table ?<br> Did you try to "explain" the query after dropping the 1st index (= like: begin;<br> DROP INDEX..; explain analyze..; rollback).<br> <br> Also, is the first (other) index btree_gin (you can \dx to show extensions)= ?<br> <br> I think it needs to be a gin index to search tags ?<br> <br> On Fri, Jan 10, 2020 at 01:42:24PM +0100, Marco Colli wrote:<br> > I would like to try your solution but I read that ALTER TABLE... SET<b= r> > STATISTICS=C2=A0 locks the table... Since it is just an experiment and= we don't<br> > know if it actually works it would be greate to avoid locking a large = table<br> > (50M) in production.<br> <br> I suggest to CREATE TABLE test_subscriptions (LIKE subscriptions INCLUDING<= br> ALL); INSERT INTO test_subscriptions SELECT * FROM subscriptions; ANALYZE t= est_subscriptions;<br> <br> Anyway, ALTER..SET STATS requires a strong lock but for only a brief moment= <br> (assuming it doesn't have to wait).=C2=A0 Possibly you'd be ok doin= g SET<br> statement_timeout=3D'1s'; ALTER TABLE....=C2=A0 <br> <br> > Does CREATE=C2=A0 STATISTICS lock the table too?<br> <br> You can check by SET client_min_messages=3Ddebug; SET lock_timeout=3D333; S= ET log_lock_waits=3Don;<br> Looks like it needs ShareUpdateExclusiveLock.<br> <br> > Does statistics work on an array field like tags? (I can't find an= y<br> > information)<br> <br> It think it'd be data type agnostic.=C2=A0 And seems to work with array= s.<br> <br> On Fri, Jan 10, 2020 at 02:30:27PM +0100, Marco Colli wrote:<br> > @Justin Pryzby I have tried this as you suggested:<br> > <br> > CREATE STATISTICS statistics_on_subscriptions_project_id_and_tags ON<b= r> > project_id, tags FROM subscriptions;<br> > VACUUM ANALYZE subscriptions;<br> > <br> > Unfortunately nothing changes and Postgresql continues to use the wron= g<br> > plan (maybe stats don't work well on array fields like tags??).<br= > <br> It'd help to see SELECT stxddependencies FROM pg_statistic_ext WHERE<br= > stxoid=3D'subscriptions'::regclass<br> </blockquote></div> --0000000000002aadbc059bca4ab7--