BUG #14608: no index scan with NOT IN and ENUM

From: lucas(at)lucas-nussbaum(dot)net
To: pgsql-bugs(at)postgresql(dot)org
Subject: BUG #14608: no index scan with NOT IN and ENUM
Date: 2017-03-31 18:53:01
Message-ID: 20170331185301.2690.64421@wrigleys.postgresql.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 14608
Logged by: Lucas Nussbaum
Email address: lucas(at)lucas-nussbaum(dot)net
PostgreSQL version: 9.6.2
Operating system: Linux (Debian stretch)
Description:

Hi,

I augment pgbench's pgbench_accounts table with an additional column that
only contains '0', '1', '2', '3' or '4'.
I set the type of this column to enum('0', '1', '2', '3', '4').
I forbid null values.
I set an index on that column.

When I do:
explain analyze select * from tt where d = '0';
the index is used, as expected.

When I do:
explain analyze select * from tt where d not in ('1', '2', '3', '4');
(which should always produce the same result as the previous query)
the index is not used and a seq scan + filter is used instead.
I would expect postgresql to figure out that "not in ('1', '2', '3', '4')"
is equivalent to "d = '0'" given that the column is NOT NULL. And use the
index.

The following code demonstrates this:

# initialize database
pgbench -i -s 100 bench

# create table from pgbench data
create table tt as select *, (aid%5)::text as d from pgbench_accounts ;
# remove lots of '0' rows (this isn't relevant, in the end, but I thought it
might)
delete from tt where d='0' and aid % 100000 <> 0;
# change column type and set NOT NULL
create type dt as enum('0', '1', '2', '3', '4');
alter table tt alter column d type dt using d::dt;
alter table tt alter column d set not null;
# add index
create index tt_d ON tt(d);

# check values and frequency:
bench=# select d, count(*) from tt group by d;
d | count
---+---------
0 | 100
3 | 2000000
4 | 2000000
2 | 2000000
1 | 2000000
(5 rows)

First case: explain analyze select * from tt where d = '0';
=> index scan, OK

Second case: explain analyze select * from tt where d not in ('1', '2', '3',
'4');
=> seq scan :-(

Thanks!

Lucas

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Andrew Gierth 2017-03-31 19:04:04 Re: BUG #14608: no index scan with NOT IN and ENUM
Previous Message Devrim Gündüz 2017-03-31 17:41:19 Re: BUG #14548: Install plv8 issue