Changeset: ef30e857ad20 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ef30e857ad20 Modified Files: sql/server/rel_optimizer.c Branch: antipush Log Message:
Added push select up optimization. This optimization will run once after all other relational optimizations to avoid infinite optimization loops with push ups and push downs. diffs (79 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 @@ -4737,6 +4737,64 @@ rel_push_join_exps_down(visitor *v, sql_ return rel; } +static bool +point_select_on_unique_column(sql_rel *rel) +{ + if (is_select(rel->op) && !list_empty(rel->exps)) { + for (node *n = rel->exps->h; n ; n = n->next) { + sql_exp *e = n->data, *el = e->l, *er = e->r, *found = NULL; + + if (is_compare(e->type) && e->flag == cmp_equal) { + if (is_numeric_upcast(el)) + el = el->l; + if (is_alias(el->type) && exp_is_atom(er) && (found = rel_find_exp(rel->l, el)) && + is_unique(found) && (!is_semantics(e) || !has_nil(el) || !has_nil(er))) + return true; + } + } + } + return false; +} + +/* + * A point select on an unique column reduces the number of rows to 1. If the same select is under a + * join, the opposite side's select can be pushed above the join. + */ +static sql_rel * +rel_push_select_up(visitor *v, sql_rel *rel) +{ + if ((is_join(rel->op) || is_semi(rel->op)) && !rel_is_ref(rel)) { + sql_rel *l = rel->l, *r = rel->r; + bool can_pushup_left = is_select(l->op) && !rel_is_ref(l), + can_pushup_right = is_select(r->op) && !rel_is_ref(r) && !is_semi(rel->op); + + if (can_pushup_left || can_pushup_right) { + if (can_pushup_left) + can_pushup_left = point_select_on_unique_column(r); + if (can_pushup_right) + can_pushup_right = point_select_on_unique_column(l); + + /* if both selects retrieve one row each, it's not worth it to push both up */ + if (can_pushup_left && !can_pushup_right) { + sql_rel *ll = l->l; + rel->l = ll; + l->l = rel; + rel = l; + assert(is_select(rel->op)); + v->changes++; + } else if (!can_pushup_left && can_pushup_right) { + sql_rel *rl = r->l; + rel->r = rl; + r->l = rel; + rel = r; + assert(is_select(rel->op)); + v->changes++; + } + } + } + return rel; +} + /* * Push {semi}joins down, pushes the joins through group by expressions. * When the join is on the group by columns, we can push the joins left @@ -9751,5 +9809,10 @@ rel_optimizer(mvc *sql, sql_rel *rel, in #ifndef NDEBUG assert(level < 20); #endif + /* Run the following optimizers only once after the others run to avoid an infinite optimization loop */ + gp = (global_props) {.cnt = {0},}; + rel_properties(sql, &gp, rel); /* collect relational tree properties */ + 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_select_up); return rel; } _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list