From 25b1dafab63f465a65c63b26834dc18857f0fa0c Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas <heikki.linnakangas@iki.fi> Date: Wed, 29 Jan 2014 18:23:17 +0200 Subject: [PATCH] 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. --- src/backend/access/gin/gindatapage.c | 38 +++++++++++++++++++++++++--- src/backend/access/gin/ginget.c | 6 +++-- src/include/access/gin_private.h | 2 +- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index 91934f0f900..9a0b8ab1f21 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -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; + + /* 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; + } - result = ginPostingListDecodeAllSegments(ptr, len, nitems); + if (len > 0) + result = ginPostingListDecodeAllSegments(seg, len, nitems); + else + { + result = NULL; + *nitems = 0; + } } else { diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 40abb3971e2..49e47c6859c 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -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++) { diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index d44d0a9fc91..ea9ae31acc0 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -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, -- GitLab