mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
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:
parent
e20c70cb0f
commit
25b1dafab6
@ -96,19 +96,49 @@ static void dataPlaceToPageLeafSplit(Buffer buf,
|
||||
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
|
||||
GinDataLeafPageGetItems(Page page, int *nitems)
|
||||
GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast)
|
||||
{
|
||||
ItemPointer result;
|
||||
|
||||
if (GinPageIsCompressed(page))
|
||||
{
|
||||
GinPostingList *ptr = GinDataLeafPageGetPostingList(page);
|
||||
GinPostingList *seg = GinDataLeafPageGetPostingList(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
|
||||
{
|
||||
|
@ -400,6 +400,7 @@ restartScanEntry:
|
||||
BlockNumber rootPostingTree = GinGetPostingTree(itup);
|
||||
GinBtreeStack *stack;
|
||||
Page page;
|
||||
ItemPointerData minItem;
|
||||
|
||||
/*
|
||||
* We should unlock entry page before touching posting tree to
|
||||
@ -426,7 +427,8 @@ restartScanEntry:
|
||||
/*
|
||||
* 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;
|
||||
|
||||
@ -558,7 +560,7 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry, ItemPointerData advan
|
||||
continue;
|
||||
}
|
||||
|
||||
entry->list = GinDataLeafPageGetItems(page, &entry->nlist);
|
||||
entry->list = GinDataLeafPageGetItems(page, &entry->nlist, advancePast);
|
||||
|
||||
for (i = 0; i < entry->nlist; i++)
|
||||
{
|
||||
|
@ -692,7 +692,7 @@ extern ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum,
|
||||
IndexTuple itup, int *nitems);
|
||||
|
||||
/* 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 BlockNumber createPostingTree(Relation index,
|
||||
ItemPointerData *items, uint32 nitems,
|
||||
|
Loading…
Reference in New Issue
Block a user