Skip to content

Commit d54c6b6

Browse files
committed
Improve some dirty code about calculation of a node rows production.
Fix the problem with full plan state tree passing. Improve AQO messaging system.
1 parent f75482f commit d54c6b6

File tree

3 files changed

+83
-57
lines changed

3 files changed

+83
-57
lines changed

aqo_pg12.patch

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
2-
index 92969636b7..42446d4e93 100644
2+
index 92969636b7..d05b07e037 100644
33
--- a/src/backend/commands/explain.c
44
+++ b/src/backend/commands/explain.c
5-
@@ -46,6 +46,9 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
5+
@@ -24,6 +24,7 @@
6+
#include "nodes/extensible.h"
7+
#include "nodes/makefuncs.h"
8+
#include "nodes/nodeFuncs.h"
9+
+#include "optimizer/cost.h"
10+
#include "parser/parsetree.h"
11+
#include "rewrite/rewriteHandler.h"
12+
#include "storage/bufmgr.h"
13+
@@ -46,6 +47,9 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
614
/* Hook for plugins to get control in explain_get_index_name() */
715
explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
816

@@ -12,7 +20,7 @@ index 92969636b7..42446d4e93 100644
1220

1321
/* OR-able flags for ExplainXMLTag() */
1422
#define X_OPENING 0
15-
@@ -596,6 +599,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
23+
@@ -596,6 +600,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
1624
ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
1725
es);
1826

@@ -22,45 +30,41 @@ index 92969636b7..42446d4e93 100644
2230
+
2331
ExplainCloseGroup("Query", NULL, true, es);
2432
}
25-
26-
@@ -1041,6 +1048,17 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
27-
return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
28-
}
29-
30-
+static bool
31-
+we_need_to_sum_tuples(const Plan *plan)
32-
+{
33-
+ if (plan->path_parallel_workers > 0 && (
34-
+ plan->parallel_aware || nodeTag(plan) == T_HashJoin ||
35-
+ nodeTag(plan) == T_MergeJoin ||
36-
+ nodeTag(plan) == T_NestLoop))
37-
+ return true;
38-
+ return false;
39-
+}
40-
+
41-
/*
42-
* ExplainNode -
43-
* Appends a description of a plan tree to es->str
44-
@@ -1523,6 +1541,24 @@ ExplainNode(PlanState *planstate, List *ancestors,
33+
34+
@@ -1523,6 +1531,38 @@ ExplainNode(PlanState *planstate, List *ancestors,
4535
appendStringInfo(es->str,
4636
" (actual rows=%.0f loops=%.0f)",
4737
rows, nloops);
38+
+
4839
+#ifdef AQO_EXPLAIN
49-
+ if (es->verbose && plan)
40+
+ if (es->verbose && plan && planstate->instrument)
5041
+ {
5142
+ int wrkrs = 1;
5243
+ double error = -1.;
5344
+
54-
+ if (planstate->worker_instrument && we_need_to_sum_tuples(plan))
55-
+ wrkrs += planstate->worker_instrument->num_workers;
45+
+ if (planstate->worker_instrument && IsParallelTuplesProcessing(plan))
46+
+ {
47+
+ int i;
48+
+ for (i = 0; i < planstate->worker_instrument->num_workers; i++)
49+
+ {
50+
+ Instrumentation *instrument = &planstate->worker_instrument->instrument[i];
51+
+ if (instrument->nloops <= 0)
52+
+ continue;
53+
+ wrkrs++;
54+
+ }
55+
+ }
5656
+
5757
+ if (plan->predicted_cardinality > 0.)
5858
+ {
59-
+ error = 100. * (plan->predicted_cardinality-(rows*wrkrs)) / (rows * wrkrs);
59+
+ error = 100. * (plan->predicted_cardinality - (rows*wrkrs))
60+
+ / plan->predicted_cardinality;
6061
+ appendStringInfo(es->str,
61-
+ " (AQO predicted: cardinality=%.0lf, error=%.0lf%%, fss=%d)",
62+
+ " (AQO predicted: cardinality=%lf, error=%.0lf%%, fsspace_hash=%d)",
6263
+ plan->predicted_cardinality, error, plan->fss_hash);
6364
+ }
65+
+ else
66+
+ appendStringInfo(es->str, " (AQO not used, fsspace_hash=%d)",
67+
+ plan->fss_hash);
6468
+ }
6569
+#endif
6670
}
@@ -84,7 +88,7 @@ index 78deade89b..b1470147e9 100644
8488
COPY_BITMAPSET_FIELD(allParam);
8589
}
8690
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
87-
index a2a9b1f7be..bc7a69bb05 100644
91+
index a2a9b1f7be..4b766b9885 100644
8892
--- a/src/backend/optimizer/path/costsize.c
8993
+++ b/src/backend/optimizer/path/costsize.c
9094
@@ -96,6 +96,10 @@
@@ -401,7 +405,22 @@ index a2a9b1f7be..bc7a69bb05 100644
401405
{
402406
double nrows;
403407

404-
@@ -5478,10 +5594,10 @@ page_size(double tuples, int width)
408+
@@ -5474,14 +5590,25 @@ page_size(double tuples, int width)
409+
return ceil(relation_byte_size(tuples, width) / BLCKSZ);
410+
}
411+
412+
+bool
413+
+IsParallelTuplesProcessing(const Plan *plan)
414+
+{
415+
+ if (plan->path_parallel_workers > 0 && (
416+
+ plan->parallel_aware || nodeTag(plan) == T_HashJoin ||
417+
+ nodeTag(plan) == T_MergeJoin ||
418+
+ nodeTag(plan) == T_NestLoop))
419+
+ return true;
420+
+ return false;
421+
+}
422+
+
423+
/*
405424
* Estimate the fraction of the work that each worker will do given the
406425
* number of workers budgeted for the path.
407426
*/
@@ -415,7 +434,7 @@ index a2a9b1f7be..bc7a69bb05 100644
415434

416435
/*
417436
* Early experience with parallel query suggests that when there is only
418-
@@ -5498,7 +5614,7 @@ get_parallel_divisor(Path *path)
437+
@@ -5498,7 +5625,7 @@ get_parallel_divisor(Path *path)
419438
{
420439
double leader_contribution;
421440

@@ -927,7 +946,7 @@ index 70f8b8e22b..d188c2596a 100644
927946
* Information for management of parameter-change-driven rescanning
928947
*
929948
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
930-
index 9b6bdbc518..4f93e222ca 100644
949+
index 9b6bdbc518..2a0caa6474 100644
931950
--- a/src/include/optimizer/cost.h
932951
+++ b/src/include/optimizer/cost.h
933952
@@ -39,6 +39,33 @@ typedef enum
@@ -998,10 +1017,11 @@ index 9b6bdbc518..4f93e222ca 100644
9981017
extern void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel);
9991018
extern void set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel);
10001019
extern void set_values_size_estimates(PlannerInfo *root, RelOptInfo *rel);
1001-
@@ -198,5 +241,6 @@ extern void set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel);
1020+
@@ -198,5 +241,7 @@ extern void set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel);
10021021
extern PathTarget *set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target);
10031022
extern double compute_bitmap_pages(PlannerInfo *root, RelOptInfo *baserel,
10041023
Path *bitmapqual, int loop_count, Cost *cost, double *tuple);
1024+
+extern bool IsParallelTuplesProcessing(const Plan *plan);
10051025
+extern double get_parallel_divisor(int parallel_workers);
10061026

10071027
#endif /* COST_H */

cardinality_estimation.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "aqo.h"
2+
#include "optimizer/optimizer.h"
23

34
/*****************************************************************************
45
*
@@ -53,5 +54,5 @@ predict_for_relation(List *restrict_clauses, List *selectivities, List *relids,
5354
if (result < 0)
5455
return -1;
5556
else
56-
return exp(result);
57+
return clamp_row_est(exp(result));
5758
}

postprocessing.c

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "aqo.h"
22
#include "access/parallel.h"
3+
#include "optimizer/optimizer.h"
34
#include "utils/queryenvironment.h"
45

56
/*****************************************************************************
@@ -184,17 +185,6 @@ restore_selectivities(List *clauselist,
184185
return lst;
185186
}
186187

187-
static bool
188-
we_need_to_sum_tuples(const Plan *plan)
189-
{
190-
if (plan->path_parallel_workers > 0 && (
191-
plan->parallel_aware || nodeTag(plan) == T_HashJoin ||
192-
nodeTag(plan) == T_MergeJoin ||
193-
nodeTag(plan) == T_NestLoop))
194-
return true;
195-
return false;
196-
}
197-
198188
/*
199189
* Walks over obtained PlanState tree, collects relation objects with their
200190
* clauses, selectivities and relids and passes each object to learn_sample.
@@ -210,8 +200,9 @@ static bool
210200
learnOnPlanState(PlanState *p, void *context)
211201
{
212202
aqo_obj_stat *ctx = (aqo_obj_stat *) context;
203+
aqo_obj_stat SubplanCtx = {NIL, NIL, NIL};
213204

214-
planstate_tree_walker(p, learnOnPlanState, context);
205+
planstate_tree_walker(p, learnOnPlanState, (void *) &SubplanCtx);
215206

216207
/*
217208
* Some nodes inserts after planning step (See T_Hash node type).
@@ -225,9 +216,11 @@ learnOnPlanState(PlanState *p, void *context)
225216
p->plan->path_relids,
226217
p->plan->path_jointype,
227218
p->plan->was_parametrized);
228-
ctx->selectivities = list_concat(ctx->selectivities, cur_selectivities);
229-
ctx->clauselist = list_concat(ctx->clauselist,
219+
SubplanCtx.selectivities = list_concat(SubplanCtx.selectivities,
220+
cur_selectivities);
221+
SubplanCtx.clauselist = list_concat(SubplanCtx.clauselist,
230222
list_copy(p->plan->path_clauses));
223+
231224
if (p->plan->path_relids != NIL)
232225
/*
233226
* This plan can be stored as cached plan. In the case we will have
@@ -246,7 +239,7 @@ learnOnPlanState(PlanState *p, void *context)
246239
if (p->instrument->nloops > 0.)
247240
{
248241
/* If we can strongly calculate produced rows, do it. */
249-
if (p->worker_instrument && we_need_to_sum_tuples(p->plan))
242+
if (p->worker_instrument && IsParallelTuplesProcessing(p->plan))
250243
{
251244
double wnloops = 0.;
252245
double wntuples = 0.;
@@ -256,6 +249,10 @@ learnOnPlanState(PlanState *p, void *context)
256249
{
257250
double t = p->worker_instrument->instrument[i].ntuples;
258251
double l = p->worker_instrument->instrument[i].nloops;
252+
253+
if (l <= 0)
254+
continue;
255+
259256
wntuples += t;
260257
wnloops += l;
261258
learn_rows += t/l;
@@ -268,7 +265,8 @@ learnOnPlanState(PlanState *p, void *context)
268265
(p->instrument->nloops - wnloops);
269266
}
270267
else
271-
/* We don't have any workers. */
268+
/* This node does not required to sum tuples of each worker
269+
* to calculate produced rows. */
272270
learn_rows = p->instrument->ntuples / p->instrument->nloops;
273271

274272
if (p->plan->predicted_cardinality > 0.)
@@ -283,8 +281,7 @@ learnOnPlanState(PlanState *p, void *context)
283281
predicted = p->plan->plan_rows;
284282

285283
/* It is needed for correct exp(result) calculation. */
286-
if (learn_rows < 1.)
287-
learn_rows = 1.;
284+
learn_rows = clamp_row_est(learn_rows);
288285
}
289286
else
290287
{
@@ -297,15 +294,20 @@ learnOnPlanState(PlanState *p, void *context)
297294
}
298295

299296
/*
300-
* Some execution logic optimizations can lead to the situation
301-
* than a subtree will never be visited.
297+
* A subtree was not visited. In this case we can not teach AQO
298+
* because ntuples value is equal to 0 and we will got learn rows == 1.
299+
* It is false teaching, because at another place of a plan
300+
* scanning of the node may produce many tuples.
302301
*/
303-
if (!(p->instrument->ntuples <= 0. && p->instrument->nloops <= 0.))
304-
learn_sample(ctx->clauselist, ctx->selectivities,
305-
ctx->relidslist, learn_rows, predicted);
302+
if (p->instrument->nloops >= 1)
303+
learn_sample(SubplanCtx.clauselist, SubplanCtx.selectivities,
304+
p->plan->path_relids, learn_rows, predicted);
306305
}
307306
}
308307

308+
ctx->clauselist = list_concat(ctx->clauselist, SubplanCtx.clauselist);
309+
ctx->selectivities = list_concat(ctx->selectivities,
310+
SubplanCtx.selectivities);
309311
return false;
310312
}
311313

@@ -429,6 +431,9 @@ aqo_ExecutorEnd(QueryDesc *queryDesc)
429431
cardinality_num_objects = 0;
430432

431433
learnOnPlanState(queryDesc->planstate, (void *) &ctx);
434+
list_free(ctx.clauselist);
435+
list_free(ctx.relidslist);
436+
list_free(ctx.selectivities);
432437
}
433438

434439
if (query_context.collect_stat)

0 commit comments

Comments
 (0)