On Sun, Jun 2, 2019 at 7:07 PM Tom Lane <t...@sss.pgh.pa.us> wrote:

> Jeff Janes <jeff.ja...@gmail.com> writes:
> > On Fri, May 24, 2019 at 11:26 AM Jeremy Finzel <finz...@gmail.com>
> wrote:
> >> I have been hoping for clearer direction from the community about
> >> specifically btree_gin indexes for low cardinality columns (as well as
> low
> >> cardinality multi-column indexes).  In general there is very little
> >> discussion about this both online and in the docs.  Rather, the emphasis
> >> for GIN indexes discussed is always on full text search of JSON
> indexing,
> >> not btree_gin indexes.
>
> I just wanted to mention that Jeremy and I had a bit of hallway-track
> discussion about this at PGCon.  The core thing to note is that the GIN
> index type was designed to deal with data types that are subdividable
> and you want to search for individual component values (array elements,
> lexemes in a text document, etc).  The btree_gin extension abuses this
> by just storing the whole values as if they were components.  AFAIR,
> the original idea for writing both btree_gin and btree_gist was to allow
> creating a single multicolumn index that covers both subdividable and
> non-subdividable columns.  The idea that btree_gin might be used on its
> own wasn't really on the radar, I don't think.


Even before 9.4 btree_gin indexes with many duplicates were still much more
compact than B-Tree, because the the value and the index tuple headers is
not repeated for each TID the way it is in B-Tree.  Of course TID list
compression has made it better yet.   I don't know what the original
motivation was for btree_gin, but multi-column GIN indexes never made much
sense to me anyway.  What do they do that can't be done just as well by
separate single-column indexes combined through BitmapAnd and BitmapOr?

Multi-column GiST indexes can be much more useful, and so btree_gist is
useful to enable things like an index over (int, int8range).

Another possible use for btree_gin is to enable use of the fastupdate
mechanism for indexes on scalars, to speed up bulk insertion but without
having to drop the index.  I've never demonstrated a realistic benefit
there, but I haven't tried very hard recently (last time I really tried was
before gin_clean_pending_list and gin_pending_list_limit were added).  The
"real" solution here is something like log-structured merge trees or
fractal indexes, but fastupdate is already here.


> However, now that GIN can compress multiple index entries for the same
> component value (which has only been true since 9.4, whereas btree_gin
> is very much older than that) it seems like it does make sense to use
> btree_gin on its own for low-cardinality non-subdividable columns.
> And that means that we ought to consider non-subdividable columns as
> fully legitimate, not just a weird corner usage.  So in particular
> I wonder whether it would be worth adding the scaffolding necessary
> to support index-only scan when the GIN opclass is one that doesn't
> subdivide the data values.
>

I wouldn't object to that, it just doesn't seem all that exciting.  But
isn't there some aspiration towards making a next generation of B-Tree
index which will also use TID list compression, making them more compact
without resorting to GIN?


> That leaves me quibbling with some points in Jeff's otherwise excellent
> reply:
>
> > For single column using a btree_gin operator, each index entry holds the
> > entire data value.  But the system doesn't know about that in any useful
> > way, so it doesn't implement index only scans, other than in the special
> > case where the value does not matter, like a 'count(*)'.  Conceptually
> > perhaps this could be fixed, but I don't see it happening. Since an
> > index-only scan is usually not much good with only a single-column
> index, I
> > don't see much excitement to improve things here.
>
> I'm confused by this; surely IOS is useful even with a single-column
> index?  Avoiding trips to the heap is always helpful.
>

But how realistic are the use cases?  My thinking was that an IOS for:

select bid from pgbench_accounts where bid=5;

would be nice if you needed to run that query, but we already know it is 5
for each row where it is 5 so we could just do the count instead of looking
at a long column of identical values.  Maybe it would be useful in joins or
something where we can't rewrite them ourselves, and the planner
can't/won't use the transitive law either.

It could be useful for disjunction in the same column, or inequality.  (Or
BETWEEN if we fix the issue you mentioned below).

select bid, count(*) from pgbench_accounts where bid = 5 or bid = 7 group
by bid;

If it can be made to support IOS, perhaps it could also be made to support
ORDER BY?

> GIN indexes over btree_gin operators do not support inequality or BETWEEN
> > queries efficiently.
>
> Are you sure about that?  It's set up to use the "partial match" logic,
> which is certainly pretty weird, but it does have the potential for
> handling inequalities efficiently.  [ pokes at it ... ]  Hm, looks like
> it does handle individual inequality conditions reasonably well, but
> it's not smart about the combination of a greater-than and a less-than
> constraint on the same column.  It ends up scanning all the entries
> satisfying the one condition, plus all the entries satisfying the other,
> then intersecting those sets --- which of course comprise the whole table
> :-(.  I think maybe this could be made better without a huge amount of
> work though.
>

That would be nice. I've hit the inefficient behavior of BETWEEN several
times "in the wild". Remembering that, this time I had only tested with the
BETWEEN, saw it was hitting every buffer in the index, and made unfounded
assumptions about the plain inequality case.

Cheers,

Jeff

Reply via email to