Re: SELECT DISTINCT never uses an index?

From: Robert Haas <robertmhaas(at)gmail(dot)com>
To: Bill Moran <wmoran(at)potentialtech(dot)com>
Cc: "pgsql-hackers(at)postgresql(dot)org" <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: SELECT DISTINCT never uses an index?
Date: 2016-07-07 21:49:27
Message-ID: CA+TgmoamRKRiQMq+vWad3aJqpoibh37=O=N9xa92rzJXBjdpYw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Thu, Jul 7, 2016 at 4:56 PM, Bill Moran <wmoran(at)potentialtech(dot)com> wrote:
> Take the following table as an example:
>
> CREATE TABLE grue (
> id SERIAL PRIMARY KEY,
> size VARCHAR(255)
> );
> CREATE INDEX grue_size ON grue(size);
>
> Now insert approximately eleventy jillion rows, but ensure
> that there are only about 20 distinct values for size.
>
> SELECT DISTINCT size FROM grue;
>
> Always does a seq scan on Postgres 9.5.2. (Yes, I know we're
> a patch behind, the upgrade is on the schedule) on
> Ubuntu 14.
>
> I would expect it to be possible, and significantly more
> efficient to do an index scan for that query.

Well, there are two possible ways to implement uniqueness: hashing and
grouping. You haven't included the EXPLAIN ANALYZE output so it's
hard to be sure which sort of plan you are getting, but my guess is
that you are getting a HashAggregate. So basically what it's doing
is:

1. Read a row.
2. Check the value in the hash table to see if we've seen it already.
3. If not, add it.
4. Go to step 1.

If you've got to visit the whole table anyway, doing it in sequential
order is smart, so this plan sounds reasonably good.

The alternative worth considering is presumably something like:

GroupAggregate
-> Index Only Scan on grue_size

Scanning an entire index in order is pretty expensive, but it seems
possible that this could be faster than the Seq Scan, especially on a
table with other wide columns, because then the index might be a lot
smaller than the table. Even if the index traversal generates some
random I/O, if it's sufficiently smaller than the table you will still
come out ahead. I'm not positive that the planner will actually
consider this plan, but it seems like it should; you might be able to
persuade it to do so by setting enable_hashagg=false, which would let
you check whether it's actually faster.

We're probably missing a few tricks on queries of this type. If the
index-traversal machinery had a mechanism to skip quickly to the next
distinct value, that could be used here: walk up the btree until you
find a page that contains keyspace not equal to the current key, then
walk back down until you find the first leaf page that contains such a
value. That would potentially let you step over large chunks of the
index without actually examining all the leaf pages, which for a query
like this seems like it could be a big win.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Corey Huinker 2016-07-07 21:52:15 \timing interval
Previous Message Bill Moran 2016-07-07 20:56:19 SELECT DISTINCT never uses an index?