From 9dcc7b38bc5ff8352268742f00f5fabd95d55a0f Mon Sep 17 00:00:00 2001 From: "Andrei V. Lepikhov" Date: Tue, 18 Mar 2025 10:40:22 +0100 Subject: [PATCH 1/3] Code (extension and the core) changes needed to be used with the explain extension --- aqo.h | 5 ++--- aqo_master.patch | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/aqo.h b/aqo.h index 8f61f4a..fe7f90d 100644 --- a/aqo.h +++ b/aqo.h @@ -144,7 +144,6 @@ #include "utils/snapmgr.h" #include "machine_learning.h" -//#include "storage.h" /* Check PostgreSQL version (9.6.0 contains important changes in planner) */ #if PG_VERSION_NUM < 90600 @@ -271,11 +270,11 @@ extern bool update_fss_ext(uint64 fs, int fss, OkNNrdata *data, List *reloids); /* Query preprocessing hooks */ extern void print_into_explain(PlannedStmt *plannedstmt, IntoClause *into, - ExplainState *es, const char *queryString, + struct ExplainState *es, const char *queryString, ParamListInfo params, const instr_time *planduration, QueryEnvironment *queryEnv); -extern void print_node_explain(ExplainState *es, PlanState *ps, Plan *plan); +extern void print_node_explain(struct ExplainState *es, PlanState *ps, Plan *plan); /* Cardinality estimation */ extern double predict_for_relation(List *restrict_clauses, List *selectivities, diff --git a/aqo_master.patch b/aqo_master.patch index e7120c7..dd87274 100644 --- a/aqo_master.patch +++ b/aqo_master.patch @@ -1,8 +1,8 @@ diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c -index 19ffcc2cacb..93934d42e30 100644 +index 22616cf7add..8a28b783f72 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c -@@ -27,6 +27,7 @@ +@@ -29,6 +29,7 @@ #include "nodes/extensible.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" @@ -10,9 +10,9 @@ index 19ffcc2cacb..93934d42e30 100644 #include "parser/analyze.h" #include "parser/parsetree.h" #include "rewrite/rewriteHandler.h" -@@ -50,6 +51,12 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL; - /* Hook for plugins to get control in explain_get_index_name() */ - explain_get_index_name_hook_type explain_get_index_name_hook = NULL; +@@ -45,6 +46,12 @@ + #include "utils/typcache.h" + #include "utils/xml.h" +/* Hook for plugins to get control in ExplainOnePlan() */ +ExplainOnePlan_hook_type ExplainOnePlan_hook = NULL; @@ -21,9 +21,9 @@ index 19ffcc2cacb..93934d42e30 100644 +ExplainOneNode_hook_type ExplainOneNode_hook = NULL; + - /* - * Various places within need to convert bytes to kilobytes. Round these up -@@ -815,6 +822,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, CachedPlan *cplan, + /* Hook for plugins to get control in ExplainOneQuery() */ + ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL; +@@ -690,6 +697,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, CachedPlan *cplan, ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3, es); @@ -34,7 +34,7 @@ index 19ffcc2cacb..93934d42e30 100644 ExplainCloseGroup("Query", NULL, true, es); } -@@ -2009,6 +2020,9 @@ ExplainNode(PlanState *planstate, List *ancestors, +@@ -1884,6 +1895,9 @@ ExplainNode(PlanState *planstate, List *ancestors, } } @@ -521,22 +521,22 @@ index 5b35debc8ff..06a7bebe4f8 100644 * estimate_num_groups - Estimate number of groups in a grouped query * diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h -index 64547bd9b9c..74792f1a8cf 100644 +index e8e92f966a1..323b3391b35 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h -@@ -87,6 +87,18 @@ extern PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook; +@@ -49,6 +49,18 @@ extern PGDLLIMPORT explain_per_node_hook_type explain_per_node_hook; typedef const char *(*explain_get_index_name_hook_type) (Oid indexId); extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook; +/* Hook for plugins to get control in ExplainOnePlan() */ +typedef void (*ExplainOnePlan_hook_type) (PlannedStmt *plannedstmt, IntoClause *into, -+ ExplainState *es, const char *queryString, ++ struct ExplainState *es, const char *queryString, + ParamListInfo params, const instr_time *planduration, + QueryEnvironment *queryEnv); +extern PGDLLIMPORT ExplainOnePlan_hook_type ExplainOnePlan_hook; + +/* Explain a node info */ -+typedef void (*ExplainOneNode_hook_type) (ExplainState *es, ++typedef void (*ExplainOneNode_hook_type) (struct ExplainState *es, + PlanState *ps, + Plan *plan); +extern PGDLLIMPORT ExplainOneNode_hook_type ExplainOneNode_hook; From 7d076843e7a0e558cf708690100d0d9ed4c1e147 Mon Sep 17 00:00:00 2001 From: "Andrei V. Lepikhov" Date: Tue, 18 Mar 2025 12:42:03 +0100 Subject: [PATCH 2/3] Changes needed to use core hooks proposed. --- aqo.c | 12 ++-- aqo.h | 15 ++-- expected/aqo_fdw.out | 34 ++++----- expected/feature_subspace.out | 4 +- expected/gucs.out | 4 +- expected/look_a_like.out | 132 +++++++++++++++++----------------- expected/parallel_workers.out | 18 ++--- expected/unsupported.out | 80 ++++++++++----------- postprocessing.c | 63 ++++++++++------ 9 files changed, 191 insertions(+), 171 deletions(-) diff --git a/aqo.c b/aqo.c index a5d4ff5..022f406 100644 --- a/aqo.c +++ b/aqo.c @@ -115,8 +115,8 @@ set_baserel_rows_estimate_hook_type prev_set_baserel_rows_estimate_hook; get_parameterized_baserel_size_hook_type prev_get_parameterized_baserel_size_hook; set_joinrel_size_estimates_hook_type prev_set_joinrel_size_estimates_hook; get_parameterized_joinrel_size_hook_type prev_get_parameterized_joinrel_size_hook; -ExplainOnePlan_hook_type prev_ExplainOnePlan_hook; -ExplainOneNode_hook_type prev_ExplainOneNode_hook; +explain_per_plan_hook_type prev_explain_per_plan_hook = NULL; +explain_per_node_hook_type prev_explain_per_node_hook = NULL; static shmem_request_hook_type prev_shmem_request_hook = NULL; static object_access_hook_type prev_object_access_hook; @@ -480,10 +480,10 @@ _PG_init(void) create_plan_hook = aqo_create_plan_hook; /* Service hooks. */ - prev_ExplainOnePlan_hook = ExplainOnePlan_hook; - ExplainOnePlan_hook = print_into_explain; - prev_ExplainOneNode_hook = ExplainOneNode_hook; - ExplainOneNode_hook = print_node_explain; + prev_explain_per_plan_hook = explain_per_plan_hook; + explain_per_plan_hook = print_into_explain; + prev_explain_per_node_hook = explain_per_node_hook; + explain_per_node_hook = print_node_explain; prev_create_upper_paths_hook = create_upper_paths_hook; create_upper_paths_hook = aqo_store_upper_signature_hook; diff --git a/aqo.h b/aqo.h index fe7f90d..1678969 100644 --- a/aqo.h +++ b/aqo.h @@ -252,8 +252,8 @@ extern set_joinrel_size_estimates_hook_type prev_set_joinrel_size_estimates_hook; extern get_parameterized_joinrel_size_hook_type prev_get_parameterized_joinrel_size_hook; -extern ExplainOnePlan_hook_type prev_ExplainOnePlan_hook; -extern ExplainOneNode_hook_type prev_ExplainOneNode_hook; +extern explain_per_plan_hook_type prev_explain_per_plan_hook; +extern explain_per_node_hook_type prev_explain_per_node_hook; extern void ppi_hook(ParamPathInfo *ppi); extern int aqo_statement_timeout; @@ -269,12 +269,15 @@ extern bool load_fss_ext(uint64 fs, int fss, OkNNrdata *data, List **reloids); extern bool update_fss_ext(uint64 fs, int fss, OkNNrdata *data, List *reloids); /* Query preprocessing hooks */ -extern void print_into_explain(PlannedStmt *plannedstmt, IntoClause *into, - struct ExplainState *es, const char *queryString, +extern void print_into_explain(PlannedStmt *ps, + IntoClause *into, + struct ExplainState *es, + const char *queryString, ParamListInfo params, - const instr_time *planduration, QueryEnvironment *queryEnv); -extern void print_node_explain(struct ExplainState *es, PlanState *ps, Plan *plan); +extern void print_node_explain(PlanState *ps, List *ancestors, + const char *relationship, const char *plan_name, + struct ExplainState *es); /* Cardinality estimation */ extern double predict_for_relation(List *restrict_clauses, List *selectivities, diff --git a/expected/aqo_fdw.out b/expected/aqo_fdw.out index 123f9a3..2ff7a44 100644 --- a/expected/aqo_fdw.out +++ b/expected/aqo_fdw.out @@ -66,9 +66,9 @@ SELECT str FROM expln(' str ----------------------------------------------------------- Foreign Scan on public.frgn (actual rows=1.00 loops=1) - AQO not used Output: x Remote SQL: SELECT x FROM public.local WHERE ((x < 10)) + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -81,9 +81,9 @@ SELECT str FROM expln(' str ----------------------------------------------------------- Foreign Scan on public.frgn (actual rows=1.00 loops=1) - AQO: rows=1, error=0% Output: x Remote SQL: SELECT x FROM public.local WHERE ((x < 10)) + AQO: rows=1, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -108,8 +108,8 @@ SELECT str FROM expln(' str --------------------------------------------------------------- Merge Join (actual rows=1.00 loops=1) - AQO not used Merge Cond: (a.x = b.x) + AQO not used -> Sort (actual rows=1.00 loops=1) Sort Key: a.x -> Foreign Scan on frgn a (actual rows=1.00 loops=1) @@ -131,10 +131,10 @@ SELECT str FROM expln(' str -------------------------------------------------------------------------------------------------------- Foreign Scan (actual rows=1.00 loops=1) - AQO: rows=1, error=0% Output: a.x, b.x Relations: (public.frgn a) INNER JOIN (public.frgn b) Remote SQL: SELECT r1.x, r2.x FROM (public.local r1 INNER JOIN public.local r2 ON (((r1.x = r2.x)))) + AQO: rows=1, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -153,8 +153,8 @@ WHERE a.aid = b.aid AND b.bval like 'val%'; QUERY PLAN ----------------------------------------------- Foreign Scan (actual rows=1000.00 loops=1) - AQO not used Relations: (frgn_a a) INNER JOIN (frgn_b b) + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -166,8 +166,8 @@ WHERE a.aid = b.aid AND b.bval like 'val%'; QUERY PLAN ----------------------------------------------- Foreign Scan (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Relations: (frgn_a a) INNER JOIN (frgn_b b) + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -207,17 +207,17 @@ WHERE str NOT LIKE '%Memory%'; Append (actual rows=1000.00 loops=1) AQO not used -> Foreign Scan (actual rows=400.00 loops=1) - AQO not used Relations: (main_p0 a_1) INNER JOIN (ref_p0 b_1) - -> Foreign Scan (actual rows=300.00 loops=1) AQO not used + -> Foreign Scan (actual rows=300.00 loops=1) Relations: (main_p1 a_2) INNER JOIN (ref_p1 b_2) - -> Hash Join (actual rows=300.00 loops=1) AQO not used + -> Hash Join (actual rows=300.00 loops=1) Hash Cond: (b_3.aid = a_3.aid) + AQO not used -> Seq Scan on ref_p2 b_3 (actual rows=300.00 loops=1) - AQO not used Filter: (bval ~~ 'val%'::text) + AQO not used -> Hash (actual rows=38.00 loops=1) -> Seq Scan on main_p2 a_3 (actual rows=38.00 loops=1) AQO not used @@ -237,17 +237,17 @@ WHERE str NOT LIKE '%Memory%'; Append (actual rows=1000.00 loops=1) AQO not used -> Foreign Scan (actual rows=400.00 loops=1) - AQO: rows=400, error=0% Relations: (main_p0 a_1) INNER JOIN (ref_p0 b_1) + AQO: rows=400, error=0% -> Foreign Scan (actual rows=300.00 loops=1) - AQO: rows=300, error=0% Relations: (main_p1 a_2) INNER JOIN (ref_p1 b_2) - -> Hash Join (actual rows=300.00 loops=1) AQO: rows=300, error=0% + -> Hash Join (actual rows=300.00 loops=1) Hash Cond: (b_3.aid = a_3.aid) + AQO: rows=300, error=0% -> Seq Scan on ref_p2 b_3 (actual rows=300.00 loops=1) - AQO: rows=300, error=0% Filter: (bval ~~ 'val%'::text) + AQO: rows=300, error=0% -> Hash (actual rows=38.00 loops=1) -> Seq Scan on main_p2 a_3 (actual rows=38.00 loops=1) AQO: rows=38, error=0% @@ -266,14 +266,14 @@ SELECT * FROM frgn AS a, frgn AS b WHERE a.x Foreign Scan on frgn a (actual rows=1.00 loops=1) AQO not used -> Materialize (actual rows=1.00 loops=1) - AQO not used Storage: Memory Maximum Storage: 17kB + AQO not used -> Foreign Scan on frgn b (actual rows=1.00 loops=1) AQO not used Using aqo: true @@ -288,10 +288,10 @@ SELECT str FROM expln(' str -------------------------------------------------------------------------------------------------------- Foreign Scan (actual rows=0.00 loops=1) - AQO: rows=1, error=100% Output: a.x, b.x Relations: (public.frgn a) INNER JOIN (public.frgn b) Remote SQL: SELECT r1.x, r2.x FROM (public.local r1 INNER JOIN public.local r2 ON (((r1.x < r2.x)))) + AQO: rows=1, error=100% Using aqo: true AQO mode: LEARN JOINS: 0 diff --git a/expected/feature_subspace.out b/expected/feature_subspace.out index 75ea3fb..3ef12af 100644 --- a/expected/feature_subspace.out +++ b/expected/feature_subspace.out @@ -31,8 +31,8 @@ WHERE str NOT LIKE '%Memory%'; result -------------------------------------------------------- Merge Left Join (actual rows=10.00 loops=1) - AQO not used Merge Cond: (a.x = b.x) + AQO not used -> Sort (actual rows=10.00 loops=1) Sort Key: a.x -> Seq Scan on a (actual rows=10.00 loops=1) @@ -54,8 +54,8 @@ WHERE str NOT LIKE '%Memory%'; result -------------------------------------------------------- Merge Left Join (actual rows=100.00 loops=1) - AQO not used Merge Cond: (b.x = a.x) + AQO not used -> Sort (actual rows=100.00 loops=1) Sort Key: b.x -> Seq Scan on b (actual rows=100.00 loops=1) diff --git a/expected/gucs.out b/expected/gucs.out index 2ec19cb..3680c5a 100644 --- a/expected/gucs.out +++ b/expected/gucs.out @@ -35,8 +35,8 @@ SELECT regexp_replace( str --------------------------------------------------- Seq Scan on public.t (actual rows=100.00 loops=1) - AQO not used Output: x + AQO not used Query Identifier: N Using aqo: true AQO mode: LEARN @@ -51,8 +51,8 @@ SELECT regexp_replace( str --------------------------------------------------- Seq Scan on public.t (actual rows=100.00 loops=1) - AQO: rows=100, error=0% Output: x + AQO: rows=100, error=0% Query Identifier: N Using aqo: true AQO mode: LEARN diff --git a/expected/look_a_like.out b/expected/look_a_like.out index a252524..79255d4 100644 --- a/expected/look_a_like.out +++ b/expected/look_a_like.out @@ -42,19 +42,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ----------------------------------------------------------- Nested Loop (actual rows=10000.00 loops=1) - AQO not used Disabled: true Output: a.x1, b.y1 + AQO not used -> Seq Scan on public.a (actual rows=100.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 Filter: ((a.x1 = 5) AND (a.x2 = 5)) Rows Removed by Filter: 900 - -> Seq Scan on public.b (actual rows=100.00 loops=100) AQO not used + -> Seq Scan on public.b (actual rows=100.00 loops=100) Output: b.y1, b.y2, b.y3 Filter: (b.y1 = 5) Rows Removed by Filter: 900 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -67,19 +67,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ----------------------------------------------------------- Nested Loop Left Join (actual rows=10000.00 loops=1) - AQO not used Disabled: true Output: a.x1, b.y1 + AQO not used -> Seq Scan on public.a (actual rows=100.00 loops=1) - AQO: rows=100, error=0% Output: a.x1, a.x2, a.x3 Filter: ((a.x1 = 5) AND (a.x2 = 5)) Rows Removed by Filter: 900 - -> Seq Scan on public.b (actual rows=100.00 loops=100) AQO: rows=100, error=0% + -> Seq Scan on public.b (actual rows=100.00 loops=100) Output: b.y1, b.y2, b.y3 Filter: (b.y1 = 5) Rows Removed by Filter: 900 + AQO: rows=100, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -92,19 +92,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result --------------------------------------------------------------- Hash Join (actual rows=50000.00 loops=1) - AQO not used Output: a.x1, b.y1 Hash Cond: (b.y1 = a.x1) + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO not used Output: b.y1, b.y2, b.y3 + AQO not used -> Hash (actual rows=500.00 loops=1) Output: a.x1 -> Seq Scan on public.a (actual rows=500.00 loops=1) - AQO not used Output: a.x1 Filter: ((a.x1 < 5) AND (a.x2 < 5)) Rows Removed by Filter: 500 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -118,19 +118,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result --------------------------------------------------------------- Hash Join (actual rows=50000.00 loops=1) - AQO: rows=50000, error=0% Output: a.x1, b.y1 Hash Cond: (b.y1 = a.x1) + AQO: rows=50000, error=0% -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% -> Hash (actual rows=500.00 loops=1) Output: a.x1 -> Seq Scan on public.a (actual rows=500.00 loops=1) - AQO: rows=500, error=0% Output: a.x1 Filter: ((a.x1 < 10) AND (a.x2 < 5)) Rows Removed by Filter: 500 + AQO: rows=500, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -143,19 +143,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result --------------------------------------------------------------- Hash Join (actual rows=70000.00 loops=1) - AQO not used Output: a.x1, b.y1 Hash Cond: (b.y1 = a.x1) + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% -> Hash (actual rows=700.00 loops=1) Output: a.x1 -> Seq Scan on public.a (actual rows=700.00 loops=1) - AQO not used Output: a.x1 Filter: ((a.x1 > 2) AND (a.x2 > 2)) Rows Removed by Filter: 300 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -168,19 +168,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------- Hash Join (actual rows=40000.00 loops=1) - AQO not used Output: a.x1, b.y1 Hash Cond: (b.y1 = a.x1) + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% -> Hash (actual rows=400.00 loops=1) Output: a.x1 -> Seq Scan on public.a (actual rows=400.00 loops=1) - AQO not used Output: a.x1 Filter: ((a.x1 > 5) AND (a.x2 > 5) AND (a.x3 < 10)) Rows Removed by Filter: 600 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -193,19 +193,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------- Hash Join (actual rows=50000.00 loops=1) - AQO not used Output: a.x1, b.y1 Hash Cond: (b.y1 = a.x1) + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% -> Hash (actual rows=500.00 loops=1) Output: a.x1 -> Seq Scan on public.a (actual rows=500.00 loops=1) - AQO not used Output: a.x1 Filter: ((a.x1 < 5) AND (a.x2 < 5) AND (a.x3 < 10)) Rows Removed by Filter: 500 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -219,19 +219,19 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ Hash Join (actual rows=40000.00 loops=1) - AQO: rows=50000, error=20% Output: a.x1, b.y1 Hash Cond: (b.y1 = a.x1) + AQO: rows=50000, error=20% -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% -> Hash (actual rows=400.00 loops=1) Output: a.x1 -> Seq Scan on public.a (actual rows=400.00 loops=1) - AQO: rows=500, error=20% Output: a.x1 Filter: ((a.x1 < 5) AND (a.x2 < 4) AND (a.x3 < 5)) Rows Removed by Filter: 600 + AQO: rows=500, error=20% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -244,21 +244,21 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=2.00 loops=1) - AQO not used Output: a.x1 Group Key: a.x1 + AQO not used -> Nested Loop (actual rows=200000.00 loops=1) - AQO not used Disabled: true Output: a.x1 + AQO not used -> Seq Scan on public.a (actual rows=200.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 Filter: ((a.x1 < 4) AND (a.x3 > 1)) Rows Removed by Filter: 800 + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=200) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -272,21 +272,21 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=2.00 loops=1) - AQO: rows=2, error=0% Output: a.x1 Group Key: a.x1 + AQO: rows=2, error=0% -> Nested Loop (actual rows=200000.00 loops=1) - AQO: rows=200000, error=0% Disabled: true Output: a.x1 + AQO: rows=200000, error=0% -> Seq Scan on public.a (actual rows=200.00 loops=1) - AQO: rows=200, error=0% Output: a.x1, a.x2, a.x3 Filter: ((a.x1 < 4) AND (a.x3 > 1)) Rows Removed by Filter: 800 + AQO: rows=200, error=0% -> Seq Scan on public.b (actual rows=1000.00 loops=200) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -299,21 +299,21 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=1.00 loops=1) - AQO: rows=2, error=50% Output: a.x1 Group Key: a.x1 + AQO: rows=2, error=50% -> Nested Loop (actual rows=100000.00 loops=1) - AQO: rows=200000, error=50% Disabled: true Output: a.x1 + AQO: rows=200000, error=50% -> Seq Scan on public.a (actual rows=100.00 loops=1) - AQO: rows=200, error=50% Output: a.x1, a.x2, a.x3 Filter: ((a.x1 < 4) AND (a.x3 > 2)) Rows Removed by Filter: 900 + AQO: rows=200, error=50% -> Seq Scan on public.b (actual rows=1000.00 loops=100) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -326,21 +326,21 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=1.00 loops=1) - AQO not used Output: a.x1 Group Key: a.x1 + AQO not used -> Nested Loop (actual rows=100000.00 loops=1) - AQO not used Disabled: true Output: a.x1 + AQO not used -> Seq Scan on public.a (actual rows=100.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 Filter: ((a.x1 < 3) AND (a.x2 < 5) AND (a.x3 > 1)) Rows Removed by Filter: 900 + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=100) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -353,21 +353,21 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=2.00 loops=1) - AQO not used Output: a.x1 Group Key: a.x1 + AQO not used -> Nested Loop (actual rows=200000.00 loops=1) - AQO not used Disabled: true Output: a.x1 + AQO not used -> Seq Scan on public.a (actual rows=200.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 Filter: ((a.x1 > 1) AND (a.x2 < 4) AND (a.x3 > 1)) Rows Removed by Filter: 800 + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=200) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -380,21 +380,21 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=2.00 loops=1) - AQO not used Output: a.x1 Group Key: a.x1 + AQO not used -> Nested Loop (actual rows=200000.00 loops=1) - AQO not used Disabled: true Output: a.x1 + AQO not used -> Seq Scan on public.a (actual rows=200.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 Filter: ((a.x1 > 1) AND (a.x2 < 4) AND (a.x3 < 5)) Rows Removed by Filter: 800 + AQO not used -> Seq Scan on public.b (actual rows=1000.00 loops=200) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -407,23 +407,23 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=2.00 loops=1) - AQO not used Output: a.x1 Group Key: a.x1 + AQO not used -> Nested Loop (actual rows=140000.00 loops=1) - AQO not used Disabled: true Output: a.x1 + AQO not used -> Seq Scan on public.a (actual rows=200.00 loops=1) - AQO: rows=100, error=-100% Output: a.x1, a.x2, a.x3 Filter: ((a.x1 < 4) AND (a.x2 < 5) AND (a.x3 > 1)) Rows Removed by Filter: 800 + AQO: rows=100, error=-100% -> Seq Scan on public.b (actual rows=700.00 loops=200) - AQO not used Output: b.y1, b.y2, b.y3 Filter: (b.y1 > 2) Rows Removed by Filter: 300 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 1 @@ -437,23 +437,23 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ------------------------------------------------------------------ HashAggregate (actual rows=1.00 loops=1) - AQO: rows=2, error=50% Output: a.x1 Group Key: a.x1 + AQO: rows=2, error=50% -> Nested Loop (actual rows=70000.00 loops=1) - AQO: rows=140000, error=50% Disabled: true Output: a.x1 + AQO: rows=140000, error=50% -> Seq Scan on public.a (actual rows=100.00 loops=1) - AQO: rows=200, error=50% Output: a.x1, a.x2, a.x3 Filter: ((a.x1 < 3) AND (a.x2 < 4) AND (a.x3 > 1)) Rows Removed by Filter: 900 + AQO: rows=200, error=50% -> Seq Scan on public.b (actual rows=700.00 loops=100) - AQO: rows=700, error=0% Output: b.y1, b.y2, b.y3 Filter: (b.y1 > 2) Rows Removed by Filter: 300 + AQO: rows=700, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -469,26 +469,26 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ---------------------------------------------------------------------- Hash Left Join (actual rows=0.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3, b.y1, b.y2, b.y3 Hash Cond: (a.x1 = b.y1) + AQO not used -> Hash Anti Join (actual rows=0.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 Hash Cond: (a.x1 = c.z1) + AQO not used -> Seq Scan on public.a (actual rows=1000.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3 + AQO not used -> Hash (actual rows=1000.00 loops=1) Output: c.z1 -> Seq Scan on public.c (actual rows=1000.00 loops=1) - AQO not used Output: c.z1 + AQO not used -> Hash (never executed) Output: b.y1, b.y2, b.y3 -> Seq Scan on public.b (never executed) - AQO: rows=1000 Output: b.y1, b.y2, b.y3 + AQO: rows=1000 Using aqo: true AQO mode: LEARN JOINS: 1 @@ -501,26 +501,26 @@ WHERE str NOT LIKE 'Query Identifier%' and str NOT LIKE '%Memory%' and str NOT L result ---------------------------------------------------------------------- Hash Left Join (actual rows=10000000.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3, b.y1, b.y2, b.y3, c.z1, c.z2, c.z3 Hash Cond: (a.x1 = c.z1) + AQO not used -> Hash Left Join (actual rows=100000.00 loops=1) - AQO not used Output: a.x1, a.x2, a.x3, b.y1, b.y2, b.y3 Hash Cond: (a.x1 = b.y1) + AQO not used -> Seq Scan on public.a (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: a.x1, a.x2, a.x3 + AQO: rows=1000, error=0% -> Hash (actual rows=1000.00 loops=1) Output: b.y1, b.y2, b.y3 -> Seq Scan on public.b (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: b.y1, b.y2, b.y3 + AQO: rows=1000, error=0% -> Hash (actual rows=1000.00 loops=1) Output: c.z1, c.z2, c.z3 -> Seq Scan on public.c (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Output: c.z1, c.z2, c.z3 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 diff --git a/expected/parallel_workers.out b/expected/parallel_workers.out index 6f4e8d3..347cc9e 100644 --- a/expected/parallel_workers.out +++ b/expected/parallel_workers.out @@ -47,9 +47,9 @@ WHERE str NOT LIKE '%Worker%'; -> Partial Aggregate (actual rows=1.00 loops=3) AQO not used -> Parallel Seq Scan on t (actual rows=333.33 loops=3) - AQO: rows=1000, error=0% Filter: ((id % '100'::numeric) = '0'::numeric) Rows Removed by Filter: 33000 + AQO: rows=1000, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -81,37 +81,37 @@ WHERE str NOT LIKE '%Workers%' AND str NOT LIKE '%Sort Method%' Aggregate (actual rows=1.00 loops=1) AQO not used -> Merge Join (actual rows=0.00 loops=1) - AQO not used Merge Cond: (t.id = q2.id) + AQO not used -> Group (actual rows=1000.00 loops=1) - AQO not used Group Key: t.id + AQO not used AQO: rows=914, error=-9% -> Sort (actual rows=333.33 loops=3) - AQO: rows=914, error=64% Sort Key: t.id + AQO: rows=914, error=64% -> Parallel Seq Scan on t (actual rows=333.33 loops=3) - AQO: rows=914, error=-9% Filter: ((id % '100'::numeric) = '0'::numeric) Rows Removed by Filter: 33000 + AQO: rows=914, error=-9% -> Sort (actual rows=1.00 loops=1) Sort Key: q2.id -> Subquery Scan on q2 (actual rows=1.00 loops=1) AQO not used -> Finalize GroupAggregate (actual rows=1.00 loops=1) - AQO not used Group Key: t_1.payload + AQO not used AQO not used -> Partial GroupAggregate (actual rows=1.00 loops=3) - AQO not used Group Key: t_1.payload + AQO not used -> Sort (actual rows=330.00 loops=3) - AQO not used Sort Key: t_1.payload + AQO not used -> Parallel Seq Scan on t t_1 (actual rows=330.00 loops=3) - AQO: rows=914, error=-8% Filter: ((id % '101'::numeric) = '0'::numeric) Rows Removed by Filter: 33003 + AQO: rows=914, error=-8% Using aqo: true AQO mode: LEARN JOINS: 1 diff --git a/expected/unsupported.out b/expected/unsupported.out index ef6af46..42295e5 100644 --- a/expected/unsupported.out +++ b/expected/unsupported.out @@ -37,11 +37,11 @@ EXPLAIN (COSTS OFF) Aggregate AQO not used -> HashAggregate - AQO: rows=17 Group Key: t.x + AQO: rows=17 -> Seq Scan on t - AQO: rows=801 Filter: (x > 3) + AQO: rows=801 Using aqo: true AQO mode: LEARN JOINS: 0 @@ -54,12 +54,12 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) str -------------------------------------------------- HashAggregate (actual rows=17.00 loops=1) - AQO not used Group Key: x + AQO not used -> Seq Scan on t (actual rows=801.00 loops=1) - AQO not used Filter: (x > 3) Rows Removed by Filter: 199 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -81,8 +81,8 @@ EXPLAIN (COSTS OFF) Aggregate AQO not used -> HashAggregate - AQO: rows=10 Group Key: t1.x, t1.y + AQO: rows=10 -> Seq Scan on t1 AQO: rows=1000 Using aqo: true @@ -103,8 +103,8 @@ EXPLAIN (COSTS OFF) Aggregate AQO not used -> HashAggregate - AQO: rows=10 Group Key: t1.x, (t1.x * t1.y) + AQO: rows=10 -> Seq Scan on t1 AQO: rows=1000 Using aqo: true @@ -146,11 +146,11 @@ WHERE q2.x > 1; Aggregate AQO not used -> Aggregate - AQO not used Filter: (count(*) > 1) + AQO not used -> HashAggregate - AQO: rows=10 Group Key: t1.x, t1.y + AQO: rows=10 -> Seq Scan on t1 AQO: rows=1000 Using aqo: true @@ -174,11 +174,11 @@ EXPLAIN (COSTS OFF) Aggregate AQO not used -> MixedAggregate - AQO not used Hash Key: t1.x, t1.y Hash Key: t1.x Hash Key: t1.y Group Key: () + AQO not used -> Seq Scan on t1 AQO: rows=1000 Using aqo: true @@ -207,13 +207,13 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) -> Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t t_1 (actual rows=50.00 loops=1) - AQO: rows=50, error=0% Filter: (x = 1) Rows Removed by Filter: 950 + AQO: rows=50, error=0% -> Seq Scan on t (actual rows=50.00 loops=1) - AQO: rows=50, error=0% Filter: ((x)::numeric = (InitPlan 1).col1) Rows Removed by Filter: 950 + AQO: rows=50, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -234,15 +234,15 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Filter: ((x)::numeric = (SubPlan 1)) + AQO: rows=1000, error=0% SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=49.90 loops=1000) - AQO: rows=50, error=0% Filter: (x = t.x) Rows Removed by Filter: 950 + AQO: rows=50, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -258,23 +258,23 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t (actual rows=0.00 loops=1) - AQO not used Filter: (((x)::numeric = (SubPlan 1)) OR (ANY ((x)::numeric = (SubPlan 2).col1))) Rows Removed by Filter: 1000 + AQO not used SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=0.00 loops=1000) - AQO not used Filter: (x = (t.x + 21)) Rows Removed by Filter: 1000 + AQO not used SubPlan 2 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0_1 (actual rows=0.00 loops=1000) - AQO not used Filter: (x = (t.x + 21)) Rows Removed by Filter: 1000 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -289,23 +289,23 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t (actual rows=0.00 loops=1) - AQO: rows=1, error=100% Filter: (((x)::numeric = (SubPlan 1)) OR (ANY ((x)::numeric = (SubPlan 2).col1))) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=0.00 loops=1000) - AQO: rows=1, error=100% Filter: (x = (t.x + 21)) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% SubPlan 2 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0_1 (actual rows=0.00 loops=1000) - AQO: rows=1, error=100% Filter: (x = (t.x + 21)) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -321,23 +321,23 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t (actual rows=0.00 loops=1) - AQO: rows=1, error=100% Filter: (((x)::numeric = (SubPlan 1)) OR (ANY ((x)::numeric = (SubPlan 2).col1))) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=0.00 loops=1000) - AQO: rows=1, error=100% Filter: (x = (t.x + 22)) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% SubPlan 2 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0_1 (actual rows=0.00 loops=1000) - AQO: rows=1, error=100% Filter: (x = (t.x + 23)) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -367,30 +367,30 @@ SELECT count(*) FROM Aggregate (actual rows=1.00 loops=1) AQO not used -> Hash Join (actual rows=42550.00 loops=1) - AQO: rows=42550, error=0% Hash Cond: ((t_1.x + 1) = t.x) + AQO: rows=42550, error=0% -> Seq Scan on t t_1 (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Filter: (((x % 3))::numeric < (SubPlan 2)) + AQO: rows=1000, error=0% SubPlan 2 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0_1 (actual rows=950.10 loops=1000) - AQO: rows=950, error=-0% Filter: (x <> t_1.x) Rows Removed by Filter: 50 + AQO: rows=950, error=-0% -> Hash (actual rows=851.00 loops=1) -> Seq Scan on t (actual rows=851.00 loops=1) - AQO: rows=851, error=0% Filter: (((x % 3))::numeric < (SubPlan 1)) Rows Removed by Filter: 149 + AQO: rows=851, error=0% SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=49.90 loops=1000) - AQO: rows=50, error=0% Filter: (x = t.x) Rows Removed by Filter: 950 + AQO: rows=50, error=0% Using aqo: true AQO mode: LEARN JOINS: 1 @@ -405,22 +405,22 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t (actual rows=1000.00 loops=1) - AQO not used Filter: ((SubPlan 1) = (SubPlan 2)) + AQO not used SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=49.90 loops=1000) - AQO not used Filter: (x = t.x) Rows Removed by Filter: 950 + AQO not used SubPlan 2 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0_1 (actual rows=49.90 loops=1000) - AQO not used Filter: (x = t.x) Rows Removed by Filter: 950 + AQO not used Using aqo: true AQO mode: LEARN JOINS: 0 @@ -434,22 +434,22 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Seq Scan on t (actual rows=1000.00 loops=1) - AQO: rows=1000, error=0% Filter: ((SubPlan 1) = (SubPlan 2)) + AQO: rows=1000, error=0% SubPlan 1 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0 (actual rows=49.90 loops=1000) - AQO: rows=50, error=0% Filter: (x = t.x) Rows Removed by Filter: 950 + AQO: rows=50, error=0% SubPlan 2 -> Aggregate (actual rows=1.00 loops=1000) AQO not used -> Seq Scan on t t0_1 (actual rows=49.90 loops=1000) - AQO: rows=50, error=0% Filter: (x = t.x) Rows Removed by Filter: 950 + AQO: rows=50, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -476,15 +476,15 @@ SELECT * FROM QUERY PLAN ------------------------------------------------ Nested Loop (actual rows=0.00 loops=1) - AQO: rows=1, error=100% Join Filter: (t.x = t_1.x) + AQO: rows=1, error=100% -> Seq Scan on t (actual rows=0.00 loops=1) - AQO: rows=1, error=100% Filter: (x < 0) Rows Removed by Filter: 1000 + AQO: rows=1, error=100% -> Seq Scan on t t_1 (never executed) - AQO: rows=1 Filter: (x > 20) + AQO: rows=1 Using aqo: true AQO mode: LEARN JOINS: 0 @@ -513,12 +513,12 @@ EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, SUMMARY OFF, BUFFERS OFF) Aggregate (actual rows=1.00 loops=1) AQO not used -> Index Only Scan using ind1 on t (actual rows=50.00 loops=1) - AQO: rows=50, error=0% Index Cond: (x < 3) Filter: (mod(x, 3) = 1) Rows Removed by Filter: 99 Heap Fetches: 149 Index Searches: 1 + AQO: rows=50, error=0% Using aqo: true AQO mode: LEARN JOINS: 0 @@ -540,13 +540,13 @@ WHERE str NOT LIKE '%Heap Blocks%'; str -------------------------------------------------------------------- Aggregate (actual rows=1.00 loops=1) - AQO not used Output: count(*) + AQO not used -> Bitmap Heap Scan on public.t (actual rows=50.00 loops=1) - AQO: rows=50, error=0% Recheck Cond: (mod(t.x, 3) = 1) Filter: (t.x < 3) Rows Removed by Filter: 300 + AQO: rows=50, error=0% -> Bitmap Index Scan on ind2 (actual rows=350.00 loops=1) Index Cond: (mod(t.x, 3) = 1) Index Searches: 1 @@ -564,9 +564,9 @@ EXPLAIN (COSTS OFF) Aggregate AQO not used -> Index Only Scan using ind1 on t - AQO: rows=50 Index Cond: (x < 3) Filter: (mod(x, 3) = 1) + AQO: rows=50 Using aqo: true AQO mode: LEARN JOINS: 0 diff --git a/postprocessing.c b/postprocessing.c index 3d50062..b369b3c 100644 --- a/postprocessing.c +++ b/postprocessing.c @@ -979,15 +979,18 @@ ExtractFromQueryEnv(QueryDesc *queryDesc) } void -print_node_explain(ExplainState *es, PlanState *ps, Plan *plan) +print_node_explain(PlanState *ps, List *ancestors, + const char *relationship, const char *plan_name, + struct ExplainState *es) { + Plan *plan = ps->plan; int wrkrs = 1; double error = -1.; AQOPlanNode *aqo_node; /* Extension, which took a hook early can be executed early too. */ - if (prev_ExplainOneNode_hook) - prev_ExplainOneNode_hook(es, ps, plan); + if (prev_explain_per_node_hook) + prev_explain_per_node_hook(ps, ancestors, relationship, plan_name, es); if (IsQueryDisabled() || !plan || es->format != EXPLAIN_FORMAT_TEXT) return; @@ -1019,44 +1022,58 @@ print_node_explain(ExplainState *es, PlanState *ps, Plan *plan) } explain_print: - appendStringInfoChar(es->str, '\n'); - if (es->str->len == 0 || es->str->data[es->str->len - 1] == '\n') - appendStringInfoSpaces(es->str, es->indent * 2); - - if (aqo_node->prediction > 0.) + if (es->format == EXPLAIN_FORMAT_TEXT) { - appendStringInfo(es->str, "AQO: rows=%.0lf", aqo_node->prediction); + ExplainIndentText(es); - if (ps->instrument && ps->instrument->nloops > 0.) + if (aqo_node->prediction > 0.) { - double rows = ps->instrument->ntuples / ps->instrument->nloops; + appendStringInfo(es->str, "AQO: rows=%.0lf", aqo_node->prediction); + + if (ps->instrument && ps->instrument->nloops > 0.) + { + double rows = ps->instrument->ntuples / ps->instrument->nloops; - error = 100. * (aqo_node->prediction - (rows*wrkrs)) - / aqo_node->prediction; - appendStringInfo(es->str, ", error=%.0lf%%", error); + error = 100. * (aqo_node->prediction - (rows*wrkrs)) + / aqo_node->prediction; + appendStringInfo(es->str, ", error=%.0lf%%", error); + } + appendStringInfoChar(es->str, '\n'); } + else + appendStringInfo(es->str, "AQO not used\n"); } else - appendStringInfo(es->str, "AQO not used"); + { + /* TODO */ + } explain_end: /* XXX: Do we really have situations when the plan is a NULL pointer? */ - if (plan && aqo_show_hash) - appendStringInfo(es->str, ", fss=%d", aqo_node->fss); + if (es->format == EXPLAIN_FORMAT_TEXT) + { + if (plan && aqo_show_hash) + { + ExplainIndentText(es); + appendStringInfo(es->str, ", fss=%d\n", aqo_node->fss); + } + } + else + { + /* TODO */ + } } /* * Prints if the plan was constructed with AQO. */ void -print_into_explain(PlannedStmt *plannedstmt, IntoClause *into, +print_into_explain(PlannedStmt *ps, IntoClause *into, ExplainState *es, const char *queryString, - ParamListInfo params, const instr_time *planduration, - QueryEnvironment *queryEnv) + ParamListInfo params, QueryEnvironment *queryEnv) { - if (prev_ExplainOnePlan_hook) - prev_ExplainOnePlan_hook(plannedstmt, into, es, queryString, - params, planduration, queryEnv); + if (prev_explain_per_plan_hook) + prev_explain_per_plan_hook(ps, into, es, queryString, params, queryEnv); if (IsQueryDisabled() || !aqo_show_details) return; From 2ecb9ce24a0bece462f4a5174907010ece723fa2 Mon Sep 17 00:00:00 2001 From: "Andrei V. Lepikhov" Date: Tue, 18 Mar 2025 12:44:52 +0100 Subject: [PATCH 3/3] Changes in the core patch we needed to fit the proposed explain hooks. --- aqo_master.patch | 69 ------------------------------------------------ 1 file changed, 69 deletions(-) diff --git a/aqo_master.patch b/aqo_master.patch index dd87274..db9caaa 100644 --- a/aqo_master.patch +++ b/aqo_master.patch @@ -1,49 +1,3 @@ -diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c -index 22616cf7add..8a28b783f72 100644 ---- a/src/backend/commands/explain.c -+++ b/src/backend/commands/explain.c -@@ -29,6 +29,7 @@ - #include "nodes/extensible.h" - #include "nodes/makefuncs.h" - #include "nodes/nodeFuncs.h" -+#include "optimizer/cost.h" - #include "parser/analyze.h" - #include "parser/parsetree.h" - #include "rewrite/rewriteHandler.h" -@@ -45,6 +46,12 @@ - #include "utils/typcache.h" - #include "utils/xml.h" - -+/* Hook for plugins to get control in ExplainOnePlan() */ -+ExplainOnePlan_hook_type ExplainOnePlan_hook = NULL; -+ -+/* Hook for plugins to get control in ExplainOnePlan() */ -+ExplainOneNode_hook_type ExplainOneNode_hook = NULL; -+ - - /* Hook for plugins to get control in ExplainOneQuery() */ - ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL; -@@ -690,6 +697,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, CachedPlan *cplan, - ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3, - es); - -+ if (ExplainOnePlan_hook) -+ ExplainOnePlan_hook(plannedstmt, into, es, -+ queryString, params, planduration, queryEnv); -+ - ExplainCloseGroup("Query", NULL, true, es); - } - -@@ -1884,6 +1895,9 @@ ExplainNode(PlanState *planstate, List *ancestors, - } - } - -+ if (ExplainOneNode_hook) -+ ExplainOneNode_hook(es, planstate, plan); -+ - /* in text format, first line ends here */ - if (es->format == EXPLAIN_FORMAT_TEXT) - appendStringInfoChar(es->str, '\n'); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 256568d05a2..914f6124e67 100644 --- a/src/backend/optimizer/path/costsize.c @@ -520,29 +474,6 @@ index 5b35debc8ff..06a7bebe4f8 100644 /* * estimate_num_groups - Estimate number of groups in a grouped query * -diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h -index e8e92f966a1..323b3391b35 100644 ---- a/src/include/commands/explain.h -+++ b/src/include/commands/explain.h -@@ -49,6 +49,18 @@ extern PGDLLIMPORT explain_per_node_hook_type explain_per_node_hook; - typedef const char *(*explain_get_index_name_hook_type) (Oid indexId); - extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook; - -+/* Hook for plugins to get control in ExplainOnePlan() */ -+typedef void (*ExplainOnePlan_hook_type) (PlannedStmt *plannedstmt, IntoClause *into, -+ struct ExplainState *es, const char *queryString, -+ ParamListInfo params, const instr_time *planduration, -+ QueryEnvironment *queryEnv); -+extern PGDLLIMPORT ExplainOnePlan_hook_type ExplainOnePlan_hook; -+ -+/* Explain a node info */ -+typedef void (*ExplainOneNode_hook_type) (struct ExplainState *es, -+ PlanState *ps, -+ Plan *plan); -+extern PGDLLIMPORT ExplainOneNode_hook_type ExplainOneNode_hook; - - extern void ExplainQuery(ParseState *pstate, ExplainStmt *stmt, - ParamListInfo params, DestReceiver *dest); diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index fbf05322c75..8fcb1fadda6 100644 --- a/src/include/nodes/pathnodes.h