Re: BRIN cost estimate

From: David Rowley <david(dot)rowley(at)2ndquadrant(dot)com>
To: Emre Hasegeli <emre(at)hasegeli(dot)com>
Cc: Alvaro Herrera <alvherre(at)2ndquadrant(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: BRIN cost estimate
Date: 2017-04-06 12:13:58
Message-ID: CAKJS1f_m3Dwz+QUA87LOo0E9N6HH336G7xkZpkU4W+4P4RDmaw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 6 April 2017 at 20:01, Emre Hasegeli <emre(at)hasegeli(dot)com> wrote:
>> + /*
>> + * Charge a small amount per range tuple which we expect to match to.
>> This
>> + * is meant to reflect the costs of manipulating the bitmap. The BRIN
>> scan
>> + * will set a bit for each page in the range when we find a matching
>> + * range, so we must multiply the charge by the number of pages in the
>> + * range.
>> + */
>> + *indexTotalCost += 0.1 * cpu_operator_cost * estimatedRanges *
>> + pagesPerRange;
>
>
> Isn't BRIN executes the operator only once per range? I think we can just
> multiply cpu_operator_cost and estimatedRanges.

The above line is for the bitmap maintenance accounting, not the
scanning of the BRIN index. That's costed by:

+ *indexTotalCost += indexRanges * (cpu_index_tuple_cost + qual_op_cost);

So not the estimated matching ranges, but the total ranges, since
we'll scan all of them.

+ *indexTotalCost += 0.1 * cpu_operator_cost * estimatedRanges *
+ pagesPerRange;

This is trying to cost up the following code in bringetbitmap()

if (addrange)
{
BlockNumber pageno;

for (pageno = heapBlk;
pageno <= heapBlk + opaque->bo_pagesPerRange - 1;
pageno++)
{
MemoryContextSwitchTo(oldcxt);
tbm_add_page(tbm, pageno);
totalpages++;
MemoryContextSwitchTo(perRangeCxt);
}

I'm charging 0.1 * cpu_operator_cost for each loop we expect to
perform here. There is no tbm_add_range(), so instead, it performs a
tbm_add_page() for each page in the range, which is why I multiply
that cost by pagesPerRange.

>
>> I also noticed that you were doing:
>>
>> + if (get_index_stats_hook &&
>> + (*get_index_stats_hook) (root, index->indexoid, 1, &vardata))
>>
>> and
>>
>> + vardata.statsTuple = SearchSysCache3(STATRELATTINH,
>> + ObjectIdGetDatum(index->indexoid),
>> + Int16GetDatum(1),
>>
>> I wondered why you picked to hardcode that as 1, and I thought that's
>> surely a bug. But then looking deeper it seems to be copied from
>> btcostestimate(), which also seems to be a long-standing bug
>> introduced in a536ed53bca40cb0d199824e358a86fcfd5db7f2. I'll go write
>> a patch for that one now.
>
>
> Yes, I copy-pasted from btcostestimate().

Turns out it's not a bug in btcostestimate(). It was just intending to
only ever get the stats for the first column in the index. Not what's
needed in the BRIN case.

--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Aleksander Alekseev 2017-04-06 12:21:17 Re: [PATCH] Remove unused argument in btree_xlog_split
Previous Message Kyotaro HORIGUCHI 2017-04-06 12:06:38 Re: Interval for launching the table sync worker