Changeset: 32cc2564d980 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/32cc2564d980 Modified Files: sql/server/rel_optimize_proj.c Branch: balanced_union Log Message:
Implements rel_push_aggr_down_n_arry opt for munion op diffs (172 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 @@ -1837,6 +1837,154 @@ exps_uses_exp(list *exps, sql_exp *e) { return list_exps_uses_exp(exps, exp_relname(e), exp_name(e)); } +/* + * Rewrite aggregations over munion all. + * groupby ([ union all (a, b, c) ], [gbe], [ count, sum ] ) + * + * into + * groupby ([ union all( groupby( a, [gbe], [ count, sum] ), + * groupby( b, [gbe], [ count, sum] ), + * groupby( c, [gbe], [ count, sum] ) ], + * [gbe], [sum, sum] ) + */ +static inline sql_rel * +rel_push_aggr_down_n_arry(visitor *v, sql_rel *rel) +{ + sql_rel *g = rel; + sql_rel *u = rel->l, *ou = u; + sql_rel *r = NULL; + list *rgbe = NULL, *gbe = NULL, *exps = NULL; + node *n, *m; + + // TODO why? + if (u->op == op_project && !need_distinct(u)) + u = u->l; + + /* make sure we don't create group by on group by's */ + for (node *n = ((list*)u->l)->h; n; n = n->next) { + r = n->data; + if (r->op == op_groupby) + return rel; + } + + /* distinct should be done over the full result */ + for (n = g->exps->h; n; n = n->next) { + sql_exp *e = n->data; + sql_subfunc *af = e->f; + + if (e->type == e_atom || + e->type == e_func || + (e->type == e_aggr && + ((strcmp(af->func->base.name, "sum") && + strcmp(af->func->base.name, "count") && + strcmp(af->func->base.name, "min") && + strcmp(af->func->base.name, "max")) || + need_distinct(e)))) + return rel; + } + + for (node *n = ((list*)u->l)->h; n; n = n->next) { + r = rel_dup(n->data); + if (!is_project(r->op)) + r = rel_project(v->sql->sa, r, + rel_projections(v->sql, r, NULL, 1, 1)); + rel_rename_exps(v->sql, u->exps, r->exps); + if (u != ou) { + r = rel_project(v->sql->sa, r, NULL); + r->exps = exps_copy(v->sql, ou->exps); + rel_rename_exps(v->sql, ou->exps, r->exps); + set_processed(r); + } + if (g->r && list_length(g->r) > 0) { + list *gbe = g->r; + rgbe = exps_copy(v->sql, gbe); + } + r = rel_groupby(v->sql, r, NULL); + r->r = rgbe; + r->nrcols = g->nrcols; + r->card = g->card; + r->exps = exps_copy(v->sql, g->exps); + r->nrcols = list_length(r->exps); + set_processed(r); + + n->data = r; + } + + /* group by on primary keys which define the partioning scheme + * don't need a finalizing group by */ + /* how to check if a partition is based on some primary key ? + * */ + if (!list_empty(rel->r)) { + for (node *n = ((list*)rel->r)->h; n; n = n->next) { + sql_exp *e = n->data; + sql_column *c = NULL; + + if ((c = exp_is_pkey(rel, e)) && partition_find_part(v->sql->session->tr, c->t, NULL)) { + /* check if key is partition key */ + v->changes++; + return rel_inplace_setop_n_ary(v->sql, rel, u->l, op_munion, + rel_projections(v->sql, rel, NULL, 1, 1)); + } + } + } + + if (!list_empty(rel->r)) { + list *ogbe = rel->r; + + gbe = new_exp_list(v->sql->sa); + for (n = ogbe->h; n; n = n->next) { + sql_exp *e = n->data, *ne; + + /* group by in aggregation list */ + ne = exps_uses_exp( rel->exps, e); + if (ne) { + sql_rel *first_munion_rel = ((list*)u->l)->h->data; + ne = list_find_exp(first_munion_rel->exps, ne); + } + if (!ne) { + /* e only in the u1,u2,...un->r (group by list) */ + for (node *n = ((list*)u->l)->h; n; n = n->next) { + ne = exp_ref(v->sql, e); + list_append(((sql_rel*)n->data)->exps, ne); + } + } + assert(ne); + ne = exp_ref(v->sql, ne); + append(gbe, ne); + } + } + + u = rel_setop_n_ary(v->sql->sa, u->l, op_munion); + rel_setop_n_ary_set_exps(v->sql, u, + rel_projections(v->sql, ((list*)u->l)->h->data, NULL, 1, 1), false); + set_processed(u); + + exps = new_exp_list(v->sql->sa); + for (n = u->exps->h, m = rel->exps->h; n && m; n = n->next, m = m->next) { + sql_exp *ne, *e = n->data, *oa = m->data; + + if (oa->type == e_aggr) { + sql_subfunc *f = oa->f; + int cnt = exp_aggr_is_count(oa); + sql_subfunc *a = sql_bind_func(v->sql, "sys", (cnt)?"sum":f->func->base.name, exp_subtype(e), NULL, F_AGGR, true); + + assert(a); + /* munion of aggr result may have nils + * because sum/count of empty set */ + set_has_nil(e); + e = exp_ref(v->sql, e); + ne = exp_aggr1(v->sql->sa, e, a, need_distinct(e), 1, e->card, 1); + } else { + ne = exp_copy(v->sql, oa); + } + exp_setname(v->sql->sa, ne, exp_find_rel_name(oa), exp_name(oa)); + append(exps, ne); + } + + v->changes++; + + return rel_inplace_groupby(rel, u, gbe, exps); +} /* * Rewrite aggregations over union all. @@ -1859,9 +2007,12 @@ rel_push_aggr_down(visitor *v, sql_rel * if (u->op == op_project && !need_distinct(u)) u = u->l; - if (!u || !is_union(u->op) || need_distinct(u) || is_single(u) || !u->exps || rel_is_ref(u)) + if (!u || !(is_union(u->op) || is_munion(u->op)) || need_distinct(u) || is_single(u) || !u->exps || rel_is_ref(u)) return rel; + if (is_munion(u->op)) + return rel_push_aggr_down_n_arry(v, rel); + ul = u->l; ur = u->r; _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org