Skip to content

Commit d78736d

Browse files
author
Commitfest Bot
committed
[PATCH]: ./v1-discount-metapage-in-genericcostestimate.patch
1 parent c9e38a5 commit d78736d

File tree

9 files changed

+55
-13
lines changed

9 files changed

+55
-13
lines changed

contrib/bloom/blcost.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ blcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
3030
/* We have to visit all index tuples anyway */
3131
costs.numIndexTuples = index->tuples;
3232

33+
/* As in btcostestimate, count only the metapage as non-leaf */
34+
costs.numNonLeafPages = 1;
35+
3336
/* Use generic estimate */
3437
genericcostestimate(root, path, loop_count, &costs);
3538

src/backend/utils/adt/selfuncs.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6998,6 +6998,11 @@ index_other_operands_eval_cost(PlannerInfo *root, List *indexquals)
69986998
return qual_arg_cost;
69996999
}
70007000

7001+
/*
7002+
* Compute generic index access cost estimates.
7003+
*
7004+
* See struct GenericCosts in selfuncs.h for more info.
7005+
*/
70017006
void
70027007
genericcostestimate(PlannerInfo *root,
70037008
IndexPath *path,
@@ -7093,16 +7098,18 @@ genericcostestimate(PlannerInfo *root,
70937098
* Estimate the number of index pages that will be retrieved.
70947099
*
70957100
* We use the simplistic method of taking a pro-rata fraction of the total
7096-
* number of index pages. In effect, this counts only leaf pages and not
7097-
* any overhead such as index metapage or upper tree levels.
7101+
* number of index leaf pages. We disregard any overhead such as index
7102+
* metapages or upper tree levels.
70987103
*
70997104
* In practice access to upper index levels is often nearly free because
71007105
* those tend to stay in cache under load; moreover, the cost involved is
71017106
* highly dependent on index type. We therefore ignore such costs here
71027107
* and leave it to the caller to add a suitable charge if needed.
71037108
*/
7104-
if (index->pages > 1 && index->tuples > 1)
7105-
numIndexPages = ceil(numIndexTuples * index->pages / index->tuples);
7109+
if (index->pages > costs->numNonLeafPages && index->tuples > 1)
7110+
numIndexPages =
7111+
ceil(numIndexTuples * (index->pages - costs->numNonLeafPages)
7112+
/ index->tuples);
71067113
else
71077114
numIndexPages = 1.0;
71087115

@@ -7693,9 +7700,18 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
76937700

76947701
/*
76957702
* Now do generic index cost estimation.
7703+
*
7704+
* While we expended effort to make realistic estimates of numIndexTuples
7705+
* and num_sa_scans, we are content to count only the btree metapage as
7706+
* non-leaf. btree fanout is typically high enough that upper pages are
7707+
* few relative to leaf pages, so accounting for them would move the
7708+
* estimates at most a percent or two. Given the uncertainty in just how
7709+
* many upper pages exist in a particular index, we'll skip trying to
7710+
* handle that.
76967711
*/
76977712
costs.numIndexTuples = numIndexTuples;
76987713
costs.num_sa_scans = num_sa_scans;
7714+
costs.numNonLeafPages = 1;
76997715

77007716
genericcostestimate(root, path, loop_count, &costs);
77017717

@@ -7760,6 +7776,9 @@ hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
77607776
{
77617777
GenericCosts costs = {0};
77627778

7779+
/* As in btcostestimate, count only the metapage as non-leaf */
7780+
costs.numNonLeafPages = 1;
7781+
77637782
genericcostestimate(root, path, loop_count, &costs);
77647783

77657784
/*
@@ -7804,6 +7823,8 @@ gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
78047823
GenericCosts costs = {0};
78057824
Cost descentCost;
78067825

7826+
/* GiST has no metapage, so we treat all pages as leaf pages */
7827+
78077828
genericcostestimate(root, path, loop_count, &costs);
78087829

78097830
/*
@@ -7859,6 +7880,9 @@ spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
78597880
GenericCosts costs = {0};
78607881
Cost descentCost;
78617882

7883+
/* As in btcostestimate, count only the metapage as non-leaf */
7884+
costs.numNonLeafPages = 1;
7885+
78627886
genericcostestimate(root, path, loop_count, &costs);
78637887

78647888
/*

src/include/utils/selfuncs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ typedef struct VariableStatData
122122
* Similarly, they can set num_sa_scans to some value >= 1 for an index AM
123123
* that doesn't necessarily perform exactly one primitive index scan per
124124
* distinct combination of ScalarArrayOp array elements.
125+
* Similarly, they can set numNonLeafPages to some value >= 1 if they know
126+
* how many index pages are not leaf pages. (It's always good to count
127+
* totally non-data-bearing pages such as metapages here, since accounting
128+
* for the metapage can move cost estimates for a small index significantly.
129+
* But upper pages in large indexes may be few enough relative to leaf pages
130+
* that it's not worth trying to count them.)
125131
*/
126132
typedef struct
127133
{
@@ -136,6 +142,7 @@ typedef struct
136142
double numIndexTuples; /* number of leaf tuples visited */
137143
double spc_random_page_cost; /* relevant random_page_cost value */
138144
double num_sa_scans; /* # indexscans from ScalarArrayOpExprs */
145+
BlockNumber numNonLeafPages; /* # of index pages that are not leafs */
139146
} GenericCosts;
140147

141148
/* Hooks for plugins to get control when we ask for stats */

src/test/regress/expected/join.out

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9570,12 +9570,14 @@ drop index j1_id2_idx;
95709570
set enable_nestloop to 0;
95719571
set enable_hashjoin to 0;
95729572
set enable_sort to 0;
9573+
-- we need additional data to get the partial indexes to be preferred
9574+
insert into j1 select 2, i from generate_series(1, 100) i;
9575+
insert into j2 select 1, i from generate_series(2, 100) i;
9576+
analyze j1;
9577+
analyze j2;
95739578
-- create indexes that will be preferred over the PKs to perform the join
95749579
create index j1_id1_idx on j1 (id1) where id1 % 1000 = 1;
95759580
create index j2_id1_idx on j2 (id1) where id1 % 1000 = 1;
9576-
-- need an additional row in j2, if we want j2_id1_idx to be preferred
9577-
insert into j2 values(1,2);
9578-
analyze j2;
95799581
explain (costs off) select * from j1
95809582
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
95819583
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1;

src/test/regress/expected/memoize.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ CREATE INDEX flt_f_idx ON flt (f);
262262
INSERT INTO flt VALUES('-0.0'::float),('+0.0'::float);
263263
ANALYZE flt;
264264
SET enable_seqscan TO off;
265+
SET enable_material TO off;
265266
-- Ensure memoize operates in logical mode
266267
SELECT explain_memoize('
267268
SELECT * FROM flt f1 INNER JOIN flt f2 ON f1.f = f2.f;', false);
@@ -455,6 +456,7 @@ WHERE unique1 < 3
455456
(1 row)
456457

457458
RESET enable_seqscan;
459+
RESET enable_material;
458460
RESET enable_mergejoin;
459461
RESET work_mem;
460462
RESET hash_mem_multiplier;

src/test/regress/expected/select.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,6 @@ select unique2 from onek2 where unique2 = 11 and stringu1 < 'B';
861861
11
862862
(1 row)
863863

864-
RESET enable_indexscan;
865864
-- check multi-index cases too
866865
explain (costs off)
867866
select unique1, unique2 from onek2
@@ -908,6 +907,7 @@ select unique1, unique2 from onek2
908907
0 | 998
909908
(2 rows)
910909

910+
RESET enable_indexscan;
911911
--
912912
-- Test some corner cases that have been known to confuse the planner
913913
--

src/test/regress/sql/join.sql

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3615,14 +3615,16 @@ set enable_nestloop to 0;
36153615
set enable_hashjoin to 0;
36163616
set enable_sort to 0;
36173617

3618+
-- we need additional data to get the partial indexes to be preferred
3619+
insert into j1 select 2, i from generate_series(1, 100) i;
3620+
insert into j2 select 1, i from generate_series(2, 100) i;
3621+
analyze j1;
3622+
analyze j2;
3623+
36183624
-- create indexes that will be preferred over the PKs to perform the join
36193625
create index j1_id1_idx on j1 (id1) where id1 % 1000 = 1;
36203626
create index j2_id1_idx on j2 (id1) where id1 % 1000 = 1;
36213627

3622-
-- need an additional row in j2, if we want j2_id1_idx to be preferred
3623-
insert into j2 values(1,2);
3624-
analyze j2;
3625-
36263628
explain (costs off) select * from j1
36273629
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
36283630
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1;

src/test/regress/sql/memoize.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ INSERT INTO flt VALUES('-0.0'::float),('+0.0'::float);
139139
ANALYZE flt;
140140

141141
SET enable_seqscan TO off;
142+
SET enable_material TO off;
142143

143144
-- Ensure memoize operates in logical mode
144145
SELECT explain_memoize('
@@ -218,6 +219,7 @@ WHERE unique1 < 3
218219
WHERE t0.ten = t1.twenty AND t0.two <> t2.four OFFSET 0);
219220

220221
RESET enable_seqscan;
222+
RESET enable_material;
221223
RESET enable_mergejoin;
222224
RESET work_mem;
223225
RESET hash_mem_multiplier;

src/test/regress/sql/select.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ SET enable_indexscan TO off;
221221
explain (costs off)
222222
select unique2 from onek2 where unique2 = 11 and stringu1 < 'B';
223223
select unique2 from onek2 where unique2 = 11 and stringu1 < 'B';
224-
RESET enable_indexscan;
225224
-- check multi-index cases too
226225
explain (costs off)
227226
select unique1, unique2 from onek2
@@ -233,6 +232,7 @@ select unique1, unique2 from onek2
233232
where (unique2 = 11 and stringu1 < 'B') or unique1 = 0;
234233
select unique1, unique2 from onek2
235234
where (unique2 = 11 and stringu1 < 'B') or unique1 = 0;
235+
RESET enable_indexscan;
236236

237237
--
238238
-- Test some corner cases that have been known to confuse the planner

0 commit comments

Comments
 (0)