Further optimize multi-key GIN searches.

If we're skipping past a certain TID, avoid decoding posting list segments
that only contain smaller TIDs.

Extracted from Alexander Korotkov's fast scan patch, heavily modified.
This commit is contained in:
Heikki Linnakangas 2014-01-29 18:23:17 +02:00
parent e20c70cb0f
commit 25b1dafab6
3 changed files with 39 additions and 7 deletions

View File

@ -96,19 +96,49 @@ static void dataPlaceToPageLeafSplit(Buffer buf,
XLogRecData **prdata, Page lpage, Page rpage); XLogRecData **prdata, Page lpage, Page rpage);
/* /*
* Read all TIDs from leaf data page to single uncompressed array. * Read TIDs from leaf data page to single uncompressed array. The TIDs are
* returned in ascending order.
*
* advancePast is a hint, indicating that the caller is only interested in
* TIDs > advancePast. To return all items, use ItemPointerSetMin.
*
* Note: This function can still return items smaller than advancePast that
* are in the same posting list as the items of interest, so the caller must
* still check all the returned items. But passing it allows this function to
* skip whole posting lists.
*/ */
ItemPointer ItemPointer
GinDataLeafPageGetItems(Page page, int *nitems) GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast)
{ {
ItemPointer result; ItemPointer result;
if (GinPageIsCompressed(page)) if (GinPageIsCompressed(page))
{ {
GinPostingList *ptr = GinDataLeafPageGetPostingList(page); GinPostingList *seg = GinDataLeafPageGetPostingList(page);
Size len = GinDataLeafPageGetPostingListSize(page); Size len = GinDataLeafPageGetPostingListSize(page);
Pointer endptr = ((Pointer) seg) + len;
GinPostingList *next;
result = ginPostingListDecodeAllSegments(ptr, len, nitems); /* Skip to the segment containing advancePast+1 */
if (ItemPointerIsValid(&advancePast))
{
next = GinNextPostingListSegment(seg);
while ((Pointer) next < endptr &&
ginCompareItemPointers(&next->first, &advancePast) <= 0)
{
seg = next;
next = GinNextPostingListSegment(seg);
}
len = endptr - (Pointer) seg;
}
if (len > 0)
result = ginPostingListDecodeAllSegments(seg, len, nitems);
else
{
result = NULL;
*nitems = 0;
}
} }
else else
{ {

View File

@ -400,6 +400,7 @@ restartScanEntry:
BlockNumber rootPostingTree = GinGetPostingTree(itup); BlockNumber rootPostingTree = GinGetPostingTree(itup);
GinBtreeStack *stack; GinBtreeStack *stack;
Page page; Page page;
ItemPointerData minItem;
/* /*
* We should unlock entry page before touching posting tree to * We should unlock entry page before touching posting tree to
@ -426,7 +427,8 @@ restartScanEntry:
/* /*
* Load the first page into memory. * Load the first page into memory.
*/ */
entry->list = GinDataLeafPageGetItems(page, &entry->nlist); ItemPointerSetMin(&minItem);
entry->list = GinDataLeafPageGetItems(page, &entry->nlist, minItem);
entry->predictNumberResult = stack->predictNumber * entry->nlist; entry->predictNumberResult = stack->predictNumber * entry->nlist;
@ -558,7 +560,7 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry, ItemPointerData advan
continue; continue;
} }
entry->list = GinDataLeafPageGetItems(page, &entry->nlist); entry->list = GinDataLeafPageGetItems(page, &entry->nlist, advancePast);
for (i = 0; i < entry->nlist; i++) for (i = 0; i < entry->nlist; i++)
{ {

View File

@ -692,7 +692,7 @@ extern ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum,
IndexTuple itup, int *nitems); IndexTuple itup, int *nitems);
/* gindatapage.c */ /* gindatapage.c */
extern ItemPointer GinDataLeafPageGetItems(Page page, int *nitems); extern ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast);
extern int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm); extern int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm);
extern BlockNumber createPostingTree(Relation index, extern BlockNumber createPostingTree(Relation index,
ItemPointerData *items, uint32 nitems, ItemPointerData *items, uint32 nitems,