Re: PATCH: index-only scans with partial indexes

From: Tomas Vondra <tomas(dot)vondra(at)2ndquadrant(dot)com>
To: Kyotaro HORIGUCHI <horiguchi(dot)kyotaro(at)lab(dot)ntt(dot)co(dot)jp>
Cc: kgrittn(at)ymail(dot)com, simon(at)2ndQuadrant(dot)com, pgsql-hackers(at)postgresql(dot)org
Subject: Re: PATCH: index-only scans with partial indexes
Date: 2015-12-06 22:48:51
Message-ID: 5664BB53.2000602@2ndquadrant.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello Kyotaro-san,

Sorry for the long delay since your response in this thread :-(

On 10/14/2015 08:06 AM, Kyotaro HORIGUCHI wrote:
>
> The table t is referred to twice by different (alias) names (though
> the diferrence is made by EXPLAIN, it shows that they are different
> rels in plantree).
>
>> So we'll have these indexrinfos:
>>
>> aidx: {b=2}
>> bidx: {a=1}
>
> Yes, but each of them belongs to different rels. So,
>
>> which makes index only scans unusable.
>
> The are usable.

Yes, you're of course right. I got confused by the comment at
IndexOptInfo that says "per-index information" but as you've pointed out
it's really "per-index per-reloptinfo" which makes it perfectly suitable
for keeping the info we need.

However, I'm not sure the changes to check_partial_indexes() are correct
- particularly the first loop.

/*
* Frequently, there will be no partial indexes, so first check to
* make sure there's something useful to do here.
*/
have_partial = false;
foreach(lc, rel->indexlist)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);

/*
* index rinfos are the same to baseristrict infos for non-partial
* indexes
*/
index->indrinfos = rel->baserestrictinfo;

if (index->indpred == NIL)
continue; /* ignore non-partial indexes */

if (index->predOK)
continue; /* don't repeat work if already proven OK */

have_partial = true;
break;
}

Now, imagine we have two indexes - partial and regular. In such case the
loop will terminate after the first index (assuming predOK=true), so the
regular index won't have indrinfos set. I think we need to remove the
'break' at the end.

BTW it took me a while to understand the change at the end:

/* Search for the first rinfo that is implied by indpred */
foreach (lcr, rel->baserestrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcr);

if (predicate_implied_by(list_make1(rinfo->clause),
index->indpred))
break;
}

/* This index needs rinfos different from baserestrictinfo */
if (lcr)
{
... filter implied conditions ...
}

Is there a reason why not to simply move the second block into the if
block in the foreach loop like this?

/* Search for the first rinfo that is implied by indpred */
foreach (lcr, rel->baserestrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcr);

if (predicate_implied_by(list_make1(rinfo->clause),
index->indpred))
{
... filter implied conditions ...
break;
}
}

Otherwise the reworked patch seems fine to me, but I'll give it a bit
more testing over the next few days.

Thanks for the help so far!

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Jeff Janes 2015-12-06 23:59:25 Re: Using quicksort for every external sort run
Previous Message Thomas Munro 2015-12-06 21:45:46 Unicode collations in FreeBSD 11, DragonFly BSD 4.4 without ICU