Changeset: 8c4d80b0600e for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=8c4d80b0600e Modified Files: sql/server/rel_optimizer.c sql/server/rel_rewriter.c sql/server/rel_rewriter.h Branch: default Log Message:
Embed rel_remove_empty_select optimizer changes on the optimizers it runs on to avoid an extra AST iteration whenever empty selects/joins are generated diffs (267 lines): diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c --- a/sql/server/rel_optimizer.c +++ b/sql/server/rel_optimizer.c @@ -4468,6 +4468,9 @@ rel_push_groupby_down(visitor *v, sql_re /* * Push select down, pushes the selects through (simple) projections. Also * it cleans up the projections which become useless. + * + * WARNING - Make sure to call try_remove_empty_select macro before returning so we ensure + * possible generated empty selects will get removed without the need to call rel_remove_empty_select optimizer */ static sql_rel * rel_push_select_down(visitor *v, sql_rel *rel) @@ -4490,8 +4493,8 @@ rel_push_select_down(visitor *v, sql_rel } /* don't make changes for empty selects */ - if (is_select(rel->op) && (!rel->exps || list_length(rel->exps) == 0)) - return rel; + if (is_select(rel->op) && list_empty(rel->exps)) + return try_remove_empty_select(v, rel); /* merge 2 selects */ r = rel->l; @@ -4500,7 +4503,7 @@ rel_push_select_down(visitor *v, sql_rel rel->l = NULL; rel_destroy(rel); v->changes++; - return rel_push_select_down(v, r); + return try_remove_empty_select(v, r); } /* * Push select through semi/anti join @@ -4534,8 +4537,7 @@ rel_push_select_down(visitor *v, sql_rel } exps = rel->exps; - if (rel->op == op_project && - r && r->op == op_project && !(rel_is_ref(r))) + if (rel->op == op_project && r && r->op == op_project && !(rel_is_ref(r))) return rel_merge_projects(v, rel); /* push select through join */ @@ -4592,38 +4594,35 @@ rel_push_select_down(visitor *v, sql_rel } n = next; } - return rel; } if (is_select(rel->op) && r && r->op == op_project && !(rel_is_ref(r))){ sql_rel *pl = r->l; /* we cannot push through rank (row_number etc) functions or projects with distinct */ - if (!pl || project_unsafe(r,1)) - return rel; - - /* introduce selects under the project (if needed) */ - set_processed(pl); - for (n = exps->h; n;) { - node *next = n->next; - sql_exp *e = n->data, *ne = NULL; - - if (e->type == e_cmp) { - ne = exp_push_down_prj(v->sql, e, r, pl); - - /* can we move it down */ - if (ne && ne != e && pl->exps) { - if (!is_select(pl->op) || rel_is_ref(pl)) - r->l = pl = rel_select(v->sql->sa, pl, NULL); - rel_select_add_exp(v->sql->sa, pl, ne); - list_remove_node(exps, NULL, n); - v->changes++; + if (pl && !project_unsafe(r, 1)) { + /* introduce selects under the project (if needed) */ + set_processed(pl); + for (n = exps->h; n;) { + node *next = n->next; + sql_exp *e = n->data, *ne = NULL; + + if (e->type == e_cmp) { + ne = exp_push_down_prj(v->sql, e, r, pl); + + /* can we move it down */ + if (ne && ne != e && pl->exps) { + if (!is_select(pl->op) || rel_is_ref(pl)) + r->l = pl = rel_select(v->sql->sa, pl, NULL); + rel_select_add_exp(v->sql->sa, pl, ne); + list_remove_node(exps, NULL, n); + v->changes++; + } } - } - n = next; - } - return rel; - } - return rel; + n = next; + } + } + } + return try_remove_empty_select(v, rel); } static sql_rel * @@ -4699,6 +4698,8 @@ rel_push_select_down_join(visitor *v, sq } n = next; } + if (is_join(rel->op) && list_empty(rel->exps)) + rel->exps = NULL; /* crossproduct */ } return rel; } @@ -5037,6 +5038,8 @@ rel_join_push_exps_down(visitor *v, sql_ r->exps = rexps; } } + if (is_join(rel->op) && list_empty(rel->exps)) + rel->exps = NULL; /* crossproduct */ } return rel; } @@ -5492,7 +5495,6 @@ rel_push_select_down_union(visitor *v, s { if (is_select(rel->op) && rel->l && rel->exps) { sql_rel *u = rel->l, *ou = u; - sql_rel *s = rel; sql_rel *ul = u->l; sql_rel *ur = u->r; @@ -5528,11 +5530,12 @@ rel_push_select_down_union(visitor *v, s /* introduce selects under the set (if needed) */ set_processed(ul); set_processed(ur); - ul = rel_select(v->sql->sa, ul, NULL); - ur = rel_select(v->sql->sa, ur, NULL); - - ul->exps = exps_copy(v->sql, s->exps); - ur->exps = exps_copy(v->sql, s->exps); + if (rel_is_ref(rel) || !list_empty(rel->exps)) { /* don't generate empty selects */ + ul = rel_select(v->sql->sa, ul, NULL); + ul->exps = exps_copy(v->sql, rel->exps); + ur = rel_select(v->sql->sa, ur, NULL); + ur->exps = exps_copy(v->sql, rel->exps); + } rel = rel_inplace_setop(v->sql, rel, ul, ur, op_union, rel_projections(v->sql, rel, NULL, 1, 1)); v->changes++; @@ -9606,7 +9609,6 @@ optimize_rel(mvc *sql, sql_rel *rel, int ev = { .sql = sql, .value_based_opt = value_based_opt, .storage_based_opt = storage_based_opt }; global_props gp = (global_props) {.cnt = {0},}; rel_properties(sql, &gp, rel); - int changes = 0; TRC_DEBUG_IF(SQL_REWRITER) { int i; @@ -9691,12 +9693,8 @@ optimize_rel(mvc *sql, sql_rel *rel, int if (gp.cnt[op_union]) { rel = rel_visitor_bottomup(&v, rel, &rel_remove_union_partitions); - if (gp.cnt[op_select]) { - changes = v.changes; + if (gp.cnt[op_select]) rel = rel_visitor_topdown(&v, rel, &rel_push_select_down_union); - if (v.changes > changes) - rel = rel_visitor_bottomup(&ev, rel, &rel_remove_empty_select); - } } if (gp.cnt[op_groupby]) @@ -9724,11 +9722,8 @@ optimize_rel(mvc *sql, sql_rel *rel, int if (gp.cnt[op_join]) rel = rel_visitor_topdown(&v, rel, &rel_push_count_down); if (level <= 0) { - changes = v.changes; if (gp.cnt[op_select]) rel = rel_visitor_topdown(&v, rel, &rel_push_select_down); - if (v.changes > changes) - rel = rel_visitor_bottomup(&ev, rel, &rel_remove_empty_select); if (gp.cnt[op_join] || gp.cnt[op_semi] || gp.cnt[op_anti] || gp.cnt[op_left]) { /* push_join_down introduces semijoins */ /* rewrite semijoin (A, join(A,B)) into semijoin (A,B) */ @@ -9754,12 +9749,8 @@ optimize_rel(mvc *sql, sql_rel *rel, int /* Important -> Make sure rel_push_select_down gets called after rel_join_order, because pushing down select expressions makes rel_join_order more difficult */ - if (gp.cnt[op_select] && (gp.cnt[op_join] || gp.cnt[op_semi] || gp.cnt[op_anti] || gp.cnt[op_left] || gp.cnt[op_right])) { - changes = v.changes; + if (gp.cnt[op_select] && (gp.cnt[op_join] || gp.cnt[op_semi] || gp.cnt[op_anti] || gp.cnt[op_left] || gp.cnt[op_right])) rel = rel_visitor_topdown(&v, rel, &rel_push_select_down); - if (v.changes > changes) - rel = rel_visitor_bottomup(&ev, rel, &rel_remove_empty_select); - } if (gp.cnt[op_join] || gp.cnt[op_left] || gp.cnt[op_right] || gp.cnt[op_full] || gp.cnt[op_semi] || gp.cnt[op_anti]) rel = rel_visitor_topdown(&v, rel, &rel_simplify_fk_joins); @@ -9777,12 +9768,8 @@ optimize_rel(mvc *sql, sql_rel *rel, int if (gp.cnt[op_join] || gp.cnt[op_left] || gp.cnt[op_right] || gp.cnt[op_full] || gp.cnt[op_semi] || gp.cnt[op_anti] || gp.cnt[op_select]) { rel = rel_visitor_bottomup(&v, rel, &rel_push_func_down); - if (gp.cnt[op_select]) { - changes = v.changes; + if (gp.cnt[op_select]) rel = rel_visitor_topdown(&v, rel, &rel_push_select_down); - if (v.changes > changes) - rel = rel_visitor_bottomup(&ev, rel, &rel_remove_empty_select); - } } if (gp.cnt[op_topn] || gp.cnt[op_sample]) diff --git a/sql/server/rel_rewriter.c b/sql/server/rel_rewriter.c --- a/sql/server/rel_rewriter.c +++ b/sql/server/rel_rewriter.c @@ -208,24 +208,10 @@ rewrite_simplify(visitor *v, sql_rel *re sql_rel * rel_remove_empty_select(visitor *v, sql_rel *rel) { - if ((is_join(rel->op) || is_semi(rel->op) || is_select(rel->op) || is_project(rel->op) || is_topn(rel->op) || is_sample(rel->op)) && rel->l) { - sql_rel *l = rel->l; - if (is_select(l->op) && !(rel_is_ref(l)) && list_empty(l->exps)) { - rel->l = l->l; - l->l = NULL; - rel_destroy(l); - v->changes++; - } - } - if ((is_join(rel->op) || is_semi(rel->op) || is_set(rel->op)) && rel->r) { - sql_rel *r = rel->r; - if (is_select(r->op) && !(rel_is_ref(r)) && list_empty(r->exps)) { - rel->r = r->l; - r->l = NULL; - rel_destroy(r); - v->changes++; - } - } + if ((is_join(rel->op) || is_semi(rel->op) || is_select(rel->op) || is_project(rel->op) || is_topn(rel->op) || is_sample(rel->op)) && rel->l) + rel->l = try_remove_empty_select(v, rel->l); + if ((is_join(rel->op) || is_semi(rel->op) || is_set(rel->op)) && rel->r) + rel->r = try_remove_empty_select(v, rel->r); if (is_join(rel->op) && list_empty(rel->exps)) rel->exps = NULL; /* crossproduct */ return rel; diff --git a/sql/server/rel_rewriter.h b/sql/server/rel_rewriter.h --- a/sql/server/rel_rewriter.h +++ b/sql/server/rel_rewriter.h @@ -19,6 +19,20 @@ extern sql_exp *rewrite_simplify_exp(visitor *v, sql_rel *rel, sql_exp *e, int depth); extern sql_rel *rewrite_simplify(visitor *v, sql_rel *rel); + +static inline sql_rel * +try_remove_empty_select(visitor *v, sql_rel *rel) +{ + if (is_select(rel->op) && !(rel_is_ref(rel)) && list_empty(rel->exps)) { + sql_rel *l = rel->l; + rel->l = NULL; + rel_destroy(rel); + v->changes++; + rel = l; + } + return rel; +} + extern sql_rel *rel_remove_empty_select(visitor *v, sql_rel *rel); extern sql_exp *exp_push_down(mvc *sql, sql_exp *e, sql_rel *f, sql_rel *t); _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list