gistchoose-2.patch
text/x-diff
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/access/gist/gistutil.c | 41 | 4 |
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 8b60774..75778f6 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -379,6 +379,7 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
GISTENTRY entry,
identry[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
+ int look_further_on_equal = -1;
Assert(!GistPageIsLeaf(p));
@@ -446,6 +447,8 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
if (j < r->rd_att->natts - 1)
best_penalty[j + 1] = -1;
+
+ look_further_on_equal = -1;
}
else if (best_penalty[j] == usize)
{
@@ -468,12 +471,46 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
}
/*
- * If we find a tuple with zero penalty for all columns, there's no
- * need to examine remaining tuples; just break out of the loop and
- * return it.
+ * If we find a tuple that's exactly as good as the currently best
+ * one, we could use either one. When inserting a lot of tuples with
+ * the same or similar keys, it's preferable to descend down the same
+ * path when possible, as that's more cache-friendly. On the other
+ * hand, if all inserts land on the same leaf page, after a split,
+ * we're never going to insert anything to the other half of the
+ * split, and end up using only 50% of the available space.
+ * Distributing the inserts evenly would lead to better usage, 75%,
+ * but that destroys cache-locality. To get the best of both worlds,
+ * when we find a tuple that's equally good as the previous best, choose
+ * whether to stick to the old best, or use the new one. Once we
+ * decide to stick to the old best, we stick to that for any
+ * subsequent equally good tuples we might find. This heavily favors
+ * tuples with low offsets, but still allows some inserts to go to
+ * other subtrees.
+ */
+ if (j == r->rd_att->natts && result != i)
+ {
+ if (look_further_on_equal == -1)
+ look_further_on_equal = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
+ if (look_further_on_equal == 1)
+ {
+ result = i;
+ look_further_on_equal = -1;
+ }
+ }
+
+ /*
+ * If we find a tuple with zero penalty for all columns, and we've
+ * decided we don't want to search for another tuple with equal
+ * penalty, there's no need to examine remaining tuples; just break
+ * out of the loop and return it.
*/
if (zero_penalty)
- break;
+ {
+ if (look_further_on_equal == -1)
+ look_further_on_equal = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
+ if (look_further_on_equal == 0)
+ break;
+ }
}
return result;