Changeset: 1407c0aa2015 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/1407c0aa2015 Modified Files: sql/server/rel_optimize_proj.c Branch: balanced_union Log Message:
Implements push_join_down_munion optimizer WIP diffs (116 lines): diff --git a/sql/server/rel_optimize_proj.c b/sql/server/rel_optimize_proj.c --- a/sql/server/rel_optimize_proj.c +++ b/sql/server/rel_optimize_proj.c @@ -3524,7 +3524,8 @@ rel_push_join_down_union(visitor *v, sql nl = rel_project(v->sql->sa, nl, rel_projections(v->sql, nl, NULL, 1, 1)); nr = rel_project(v->sql->sa, nr, rel_projections(v->sql, nr, NULL, 1, 1)); v->changes++; - return rel_inplace_setop(v->sql, rel, nl, nr, op_union, rel_projections(v->sql, rel, NULL, 1, 1)); + return rel_inplace_setop(v->sql, rel, nl, nr, op_union, + rel_projections(v->sql, rel, NULL, 1, 1)); } else if (is_union(l->op) && !need_distinct(l) && !is_single(l) && is_union(r->op) && !need_distinct(r) && !is_single(r) && je) { sql_rel *nl, *nr; @@ -3684,6 +3685,102 @@ rel_push_join_down_union(visitor *v, sql return rel; } +/* + * Push (semi)joins down unions, this is basically for merge tables, where + * we know that the fk-indices are split over two clustered merge tables. + */ +static inline sql_rel * +rel_push_join_down_munion(visitor *v, sql_rel *rel) +{ + if ((is_join(rel->op) && !is_outerjoin(rel->op) && !is_single(rel)) || is_semi(rel->op)) { + sql_rel *l = rel->l, *r = rel->r, *ol = l, *or = r; + list *exps = rel->exps, *attr = rel->attr; + sql_exp *je = NULL; + + /* we would like to optimize in place reference rels which point + * to replica tables and let the replica optimizer handle those + * later. otherwise we miss the push join down optimization due + * to the rel_is_ref bailout + */ + if (rel_is_ref(l) && is_basetable(l->op) && l->l && isReplicaTable((sql_table*)l->l)) { + rel->l = rel_copy(v->sql, l, true); + rel_destroy(l); + } + if (rel_is_ref(r) && is_basetable(r->op) && r->l && isReplicaTable((sql_table*)r->l)) { + rel->r = rel_copy(v->sql, r, true); + rel_destroy(r); + } + + // TODO: do we need to check if it's l/r are refs? + if (!l || !r || need_distinct(l) || need_distinct(r) || rel_is_ref(l) || rel_is_ref(r)) + return rel; + if (l->op == op_project) + l = l->l; + if (r->op == op_project) + r = r->l; + + /* both sides only if we have a join index ASSUMING pkey-fkey are aligned */ + // TODO: we could also check if the join cols are (not) unique + bool aligned_pk_fk = true; + if (!l || !r || (is_munion(l->op) && is_munion(r->op) && + !(je = rel_is_join_on_pkey(rel, aligned_pk_fk)))) + return rel; + + // TODO: why? bailout for no semijoin without pkey joins + if (is_semi(rel->op) && is_munion(l->op) && !je) + return rel; + + if (is_munion(l->op) && !need_distinct(l) && !is_single(l) && + !is_munion(r->op)){ + /* join(munion(a,b,c), d) -> munion(join(a,d), join(b,d), join(c,d)) */ + for (node *n = ((list*)l->l)->h; n; n = n->next) { + sql_rel *pc = rel_dup(n->data); + if (!is_project(pc->op)) + pc = rel_project(v->sql->sa, pc, rel_projections(v->sql, pc, NULL, 1, 1)); + rel_rename_exps(v->sql, l->exps, pc->exps); + if (l != ol) { + pc = rel_project(v->sql->sa, pc, NULL); + pc->exps = exps_copy(v->sql, ol->exps); + set_processed(pc); + } + pc = rel_crossproduct(v->sql->sa, pc, rel_dup(or), rel->op); + pc->exps = exps_copy(v->sql, exps); + pc->attr = exps_copy(v->sql, attr); + set_processed(pc); + pc = rel_project(v->sql->sa, pc, rel_projections(v->sql, pc, NULL, 1, 1)); + n->data = pc; + } + v->changes++; + return rel_inplace_setop_n_ary(v->sql, rel, l->l, op_munion, + rel_projections(v->sql, rel, NULL, 1, 1)); + } else if (is_munion(l->op) && !need_distinct(l) && !is_single(l) && + is_munion(r->op) && !need_distinct(r) && !is_single(r) && + je) { + /* join(munion(a,b,c), union(d,e,f)) -> munion(join(a,d), join(b,e), join(c,f)) */ + // TODO + } else if (!is_munion(l->op) && + is_munion(r->op) && !need_distinct(r) && !is_single(r) && + !is_semi(rel->op)) { + /* join(a, munion(b,c,d)) -> munion(join(a,b), join(a,c), join(a,d)) */ + // TODO + } else if (!is_munion(l->op) && + is_munion(r->op) && !need_distinct(r) && !is_single(r) && + is_semi(rel->op) && je) { + /* {semi}join ( A1, munion (B, A2, C)) [A1.partkey = A2.partkey] -> + * {semi}join ( A1, A2 ) + * (ie a single part on n-th munion operand) + * + * How to detect that a relation isn't matching? + * partitioning is currently done only on pkey/fkey's + * ie only matching per part if join is on pkey/fkey (parts) + * and part numbers should match. + * */ + // TODO + } + } + return rel; +} + static sql_rel * rel_optimize_unions_topdown_(visitor *v, sql_rel *rel) { _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org