Further optimize multi-key GIN searches.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 29 Jan 2014 16:23:17 +0000 (18:23 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 29 Jan 2014 16:26:40 +0000 (18:26 +0200)
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
src/backend/access/gin/ginget.c
src/include/access/gin_private.h

index 91934f0f90099f6218c4d787b13673de6bdeab0c..9a0b8ab1f214258ece93695f96ec04a441cc3018 100644 (file)
@@ -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
        {
index 40abb3971e2dc592611a71bd5628682784526c9f..49e47c6859c57e44932aa87e1489f0e8e715f9cf 100644 (file)
@@ -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++)
                {
index d44d0a9fc9188706ca05fa1cf85a6b17c09519fd..ea9ae31acc0ea57b42740585f78de2fd893eda42 100644 (file)
@@ -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,