Re: No Index-Only Scan on Partial Index - Mailing list pgsql-hackers

From Merlin Moncure
Subject Re: No Index-Only Scan on Partial Index
Date
Msg-id CAHyXU0zbBv70e7--qQrY-L9oV-jdb4_NerVkGR-=fd7qui9ZTg@mail.gmail.com
Whole thread Raw
In response to No Index-Only Scan on Partial Index  ("David E. Wheeler" <david@justatheory.com>)
Responses Re: No Index-Only Scan on Partial Index
List pgsql-hackers
On Tue, Oct 1, 2013 at 5:35 PM, David E. Wheeler <david@justatheory.com> wrote:
> Hackers,
>
> I was trying to figure out why a query was not doing an index-only scan on a partial index, when Josh Berkus pointed
tothis issue, reported by Merlin Moncure: 
>
>   http://www.postgresql.org/message-id/CAHyXU0x1OGao48WajAfUsbXqkUDLf=_6ho6hLMB8DSfkWdaVVw@mail.gmail.com
>
> In short, the planner needs the column from the where clause included in the index to decide it can do an index-only
scan.This test case demonstrates the truth of this finding: 
>
>     CREATE TABLE try (
>         id     INT NOT NULL,
>         label  TEXT NOT NULL,
>         active BOOLEAN DEFAULT TRUE
>     );
>
>     INSERT INTO try
>     SELECT i
>          ,  (ARRAY['foo','bar','baz','wig'])[floor((random()*4))::int + 1]
>          , (i % 100) = 0
>       FROM generate_series(1, 100000) i;
>
>     VACUUM FREEZE TRY;
>
>     CREATE INDEX idx_try_active ON try(id) WHERE active;
>
>     -- Does a bitmap heap scan.
>     EXPLAIN (ANALYZE, FORMAT YAML)
>     SELECT id FROM try WHERE active;
>
>     DROP INDEX idx_try_active;
>     CREATE INDEX idx_try_active ON try(label, id, active) WHERE active;
>
>     -- Does an index-only scan.
>     EXPLAIN (ANALYZE, FORMAT YAML)
>     SELECT id FROM try WHERE active;
>
>     DROP TABLE try;
>
> The first query does a bitmap heap scan, but after the index that includes the active column is added, it does an
index-onlyscan. 
>
> However, this does not quite match my case. In my case, I'm using an immutable function call in the index where
clause:
>
>     CREATE INDEX idx_try_active ON try(id, upper_inf(irange)) WHERE upper_inf(irange);
>
> I am unable to get the planner do to an index-only scan with this index no matter what I do. Here’s the full test
case:
>
>     CREATE TABLE try (
>         id     INT       NOT NULL,
>         label  TEXT      NOT NULL,
>         irange INT4RANGE NOT NULL
>     );
>
>     INSERT INTO try
>     SELECT i
>          ,  (ARRAY['foo','bar','baz','wig'])[floor((random()*4))::int + 1]
>          , int4range(1, CASE WHEN random() < 0.01 THEN NULL ELSE 2 END)
>       FROM generate_series(1, 100000) i;
>
>     VACUUM FREEZE TRY;
>
>     CREATE INDEX idx_try_active ON try(id) WHERE upper_inf(irange);
>
>     -- Does a bitmap heap scan.
>     EXPLAIN (ANALYZE, FORMAT YAML)
>     SELECT id FROM try WHERE upper_inf(irange);
>
>     DROP INDEX idx_try_active;
>     CREATE INDEX idx_try_active ON try(label, id, upper_inf(irange)) WHERE upper_inf(irange);
>
>     -- Also does a bitmap heap scan.
>     EXPLAIN (ANALYZE, FORMAT YAML)
>     SELECT id FROM try WHERE upper_inf(irange);
>
>     DROP TABLE try;
>
> So is there something about using a function in a conditional index that prevents index-only scans? Tested on 9.2 and
9.3,BTW. 

I don't think it has anything to do with the conditional index -- it's
the functional based.  For some reason postgres always wants to post
filter (note the filter step below):

postgres=# create index on try(upper_inf(irange));
CREATE INDEX
Time: 12.001 ms
postgres=# explain select * from try where upper_inf(irange);                                 QUERY PLAN
-------------------------------------------------------------------------------Index Scan using try_upper_inf_idx on
try (cost=0.00..9.25 rows=33 width=40)  Index Cond: (upper_inf(irange) = true)  Filter: upper_inf(irange) 

merlin



pgsql-hackers by date:

Previous
From: "David E. Wheeler"
Date:
Subject: No Index-Only Scan on Partial Index
Next
From: "David E. Wheeler"
Date:
Subject: Re: No Index-Only Scan on Partial Index