Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a1c649d

Browse files
committed
Pass all scan keys to BRIN consistent function at once
This commit changes how we pass scan keys to BRIN consistent function. Instead of passing them one by one, we now pass all scan keys for a given attribute at once. That makes the consistent function a bit more complex, as it has to loop through the keys, but it does allow more elaborate opclasses that can use multiple keys to eliminate ranges much more effectively. The existing BRIN opclasses (minmax, inclusion) don't really benefit from this change. The primary purpose is to allow future opclases to benefit from seeing all keys at once. This does change the BRIN API, because the signature of the consistent function changes (a new parameter with number of scan keys). So this breaks existing opclasses, and will require supporting two variants of the code for different PostgreSQL versions. We've considered supporting two variants of the consistent, but we've decided not to do that. Firstly, there's another patch that moves handling of NULL values from the opclass, which means the opclasses need to be updated anyway. Secondly, we're not aware of any out-of-core BRIN opclasses, so it does not seem worth the extra complexity. Bump catversion, because of pg_proc changes. Author: Tomas Vondra <tomas.vondra@postgresql.org> Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Mark Dilger <hornschnorter@gmail.com> Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com> Reviewed-by: John Naylor <john.naylor@enterprisedb.com> Reviewed-by: Nikita Glukhov <n.gluhov@postgrespro.ru> Discussion: https://postgr.es/m/c1138ead-7668-f0e1-0638-c3be3237e812@2ndquadrant.com
1 parent bfa2cee commit a1c649d

File tree

7 files changed

+268
-98
lines changed

7 files changed

+268
-98
lines changed

doc/src/sgml/brin.sgml

+5-3
Original file line numberDiff line numberDiff line change
@@ -464,12 +464,14 @@ typedef struct BrinOpcInfo
464464

465465
<varlistentry>
466466
<term><function>bool consistent(BrinDesc *bdesc, BrinValues *column,
467-
ScanKey key)</function></term>
467+
ScanKey *keys, int nkeys)</function></term>
468468
<listitem>
469469
<para>
470-
Returns whether the ScanKey is consistent with the given indexed
471-
values for a range.
470+
Returns whether all the ScanKey entries are consistent with the given
471+
indexed values for a range.
472472
The attribute number to use is passed as part of the scan key.
473+
Multiple scan keys for the same attribute may be passed at once, the
474+
number of entries is determined by the <literal>nkeys</literal> parameter.
473475
</para>
474476
</listitem>
475477
</varlistentry>

src/backend/access/brin/brin.c

+83-33
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,9 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
390390
BrinMemTuple *dtup;
391391
BrinTuple *btup = NULL;
392392
Size btupsz = 0;
393+
ScanKey **keys;
394+
int *nkeys;
395+
int keyno;
393396

394397
opaque = (BrinOpaque *) scan->opaque;
395398
bdesc = opaque->bo_bdesc;
@@ -411,6 +414,65 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
411414
*/
412415
consistentFn = palloc0(sizeof(FmgrInfo) * bdesc->bd_tupdesc->natts);
413416

417+
/*
418+
* Make room for per-attribute lists of scan keys that we'll pass to the
419+
* consistent support procedure. We don't know which attributes have scan
420+
* keys, so we allocate space for all attributes. That may use more memory
421+
* but it's probably cheaper than determining which attributes are used.
422+
*
423+
* XXX The widest index can have 32 attributes, so the amount of wasted
424+
* memory is negligible. We could invent a more compact approach (with
425+
* just space for used attributes) but that would make the matching more
426+
* complex so it's not a good trade-off.
427+
*/
428+
keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts);
429+
nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts);
430+
431+
/* Preprocess the scan keys - split them into per-attribute arrays. */
432+
for (keyno = 0; keyno < scan->numberOfKeys; keyno++)
433+
{
434+
ScanKey key = &scan->keyData[keyno];
435+
AttrNumber keyattno = key->sk_attno;
436+
437+
/*
438+
* The collation of the scan key must match the collation used in the
439+
* index column (but only if the search is not IS NULL/ IS NOT NULL).
440+
* Otherwise we shouldn't be using this index ...
441+
*/
442+
Assert((key->sk_flags & SK_ISNULL) ||
443+
(key->sk_collation ==
444+
TupleDescAttr(bdesc->bd_tupdesc,
445+
keyattno - 1)->attcollation));
446+
447+
/* First time we see this attribute, so init the array of keys. */
448+
if (!keys[keyattno - 1])
449+
{
450+
FmgrInfo *tmp;
451+
452+
/*
453+
* This is a bit of an overkill - we don't know how many scan keys
454+
* are there for this attribute, so we simply allocate the largest
455+
* number possible (as if all keys were for this attribute). This
456+
* may waste a bit of memory, but we only expect small number of
457+
* scan keys in general, so this should be negligible, and
458+
* repeated repalloc calls are not free either.
459+
*/
460+
keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys);
461+
462+
/* First time this column, so look up consistent function */
463+
Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid);
464+
465+
tmp = index_getprocinfo(idxRel, keyattno,
466+
BRIN_PROCNUM_CONSISTENT);
467+
fmgr_info_copy(&consistentFn[keyattno - 1], tmp,
468+
CurrentMemoryContext);
469+
}
470+
471+
/* Add key to the per-attribute array. */
472+
keys[keyattno - 1][nkeys[keyattno - 1]] = key;
473+
nkeys[keyattno - 1]++;
474+
}
475+
414476
/* allocate an initial in-memory tuple, out of the per-range memcxt */
415477
dtup = brin_new_memtuple(bdesc);
416478

@@ -471,7 +533,7 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
471533
}
472534
else
473535
{
474-
int keyno;
536+
int attno;
475537

476538
/*
477539
* Compare scan keys with summary values stored for the range.
@@ -481,50 +543,38 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
481543
* no keys.
482544
*/
483545
addrange = true;
484-
for (keyno = 0; keyno < scan->numberOfKeys; keyno++)
546+
for (attno = 1; attno <= bdesc->bd_tupdesc->natts; attno++)
485547
{
486-
ScanKey key = &scan->keyData[keyno];
487-
AttrNumber keyattno = key->sk_attno;
488-
BrinValues *bval = &dtup->bt_columns[keyattno - 1];
548+
BrinValues *bval;
489549
Datum add;
550+
Oid collation;
490551

491-
/*
492-
* The collation of the scan key must match the collation
493-
* used in the index column (but only if the search is not
494-
* IS NULL/ IS NOT NULL). Otherwise we shouldn't be using
495-
* this index ...
496-
*/
497-
Assert((key->sk_flags & SK_ISNULL) ||
498-
(key->sk_collation ==
499-
TupleDescAttr(bdesc->bd_tupdesc,
500-
keyattno - 1)->attcollation));
501-
502-
/* First time this column? look up consistent function */
503-
if (consistentFn[keyattno - 1].fn_oid == InvalidOid)
504-
{
505-
FmgrInfo *tmp;
506-
507-
tmp = index_getprocinfo(idxRel, keyattno,
508-
BRIN_PROCNUM_CONSISTENT);
509-
fmgr_info_copy(&consistentFn[keyattno - 1], tmp,
510-
CurrentMemoryContext);
511-
}
552+
/* skip attributes without any scan keys */
553+
if (nkeys[attno - 1] == 0)
554+
continue;
555+
556+
bval = &dtup->bt_columns[attno - 1];
557+
558+
Assert((nkeys[attno - 1] > 0) &&
559+
(nkeys[attno - 1] <= scan->numberOfKeys));
512560

513561
/*
514562
* Check whether the scan key is consistent with the page
515563
* range values; if so, have the pages in the range added
516564
* to the output bitmap.
517565
*
518-
* When there are multiple scan keys, failure to meet the
519-
* criteria for a single one of them is enough to discard
520-
* the range as a whole, so break out of the loop as soon
521-
* as a false return value is obtained.
566+
* XXX We simply use the collation from the first key (it
567+
* has to be the same for all keys for the same attribue).
522568
*/
523-
add = FunctionCall3Coll(&consistentFn[keyattno - 1],
524-
key->sk_collation,
569+
collation = keys[attno - 1][0]->sk_collation;
570+
571+
/* Check all keys at once */
572+
add = FunctionCall4Coll(&consistentFn[attno - 1],
573+
collation,
525574
PointerGetDatum(bdesc),
526575
PointerGetDatum(bval),
527-
PointerGetDatum(key));
576+
PointerGetDatum(keys[attno - 1]),
577+
Int32GetDatum(nkeys[attno - 1]));
528578
addrange = DatumGetBool(add);
529579
if (!addrange)
530580
break;

0 commit comments

Comments
 (0)