Changeset: 757554481335 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/757554481335
Added Files:
        sql/server/rel_optimize_join.c
Modified Files:
        sql/server/CMakeLists.txt
        sql/server/rel_optimize_sel.c
        sql/server/rel_rel.c
        sql/server/rel_statistics.c
        sql/server/rel_statistics.h
Branch: default
Log Message:

split some of the join optimization code into rel_optimize_join.c


diffs (truncated from 4424 to 300 lines):

diff --git a/sql/server/CMakeLists.txt b/sql/server/CMakeLists.txt
--- a/sql/server/CMakeLists.txt
+++ b/sql/server/CMakeLists.txt
@@ -51,6 +51,7 @@ target_sources(sqlserver
   rel_optimize_others.c
   rel_optimize_proj.c
   rel_optimize_sel.c
+  rel_optimize_join.c
   rel_distribute.c
   rel_remote.c rel_remote.h
   rel_propagate.c rel_propagate.h
diff --git a/sql/server/rel_optimize_join.c b/sql/server/rel_optimize_join.c
new file mode 100644
--- /dev/null
+++ b/sql/server/rel_optimize_join.c
@@ -0,0 +1,2177 @@
+
+#include "monetdb_config.h"
+#include "rel_optimizer_private.h"
+#include "rel_statistics.h"
+//#include "rel_basetable.h"
+#include "rel_rewriter.h"
+//#include "sql_storage.h"
+
+static int
+find_join_rels(list **L, list **R, list *exps, list *rels)
+{
+       node *n;
+
+       *L = sa_list(exps->sa);
+       *R = sa_list(exps->sa);
+       if (!exps || list_length(exps) <= 1)
+               return -1;
+       for(n = exps->h; n; n = n->next) {
+               sql_exp *e = n->data;
+               sql_rel *l = NULL, *r = NULL;
+
+               if (!is_complex_exp(e->flag)){
+                       l = find_rel(rels, e->l);
+                       r = find_rel(rels, e->r);
+               }
+               if (l<r) {
+                       list_append(*L, l);
+                       list_append(*R, r);
+               } else {
+                       list_append(*L, r);
+                       list_append(*R, l);
+               }
+       }
+       return 0;
+}
+
+static list *
+distinct_join_exps(list *aje, list *lrels, list *rrels)
+{
+       node *n, *m, *o, *p;
+       int len = list_length(aje), i, j;
+       char *used = SA_ZNEW_ARRAY(aje->sa, char, len);
+       list *res = sa_list(aje->sa);
+
+       assert(len == list_length(lrels));
+       for(n = lrels->h, m = rrels->h, j = 0; n && m;
+           n = n->next, m = m->next, j++) {
+               if (n->data && m->data)
+               for(o = n->next, p = m->next, i = j+1; o && p;
+                   o = o->next, p = p->next, i++) {
+                       if (o->data == n->data && p->data == m->data)
+                               used[i] = 1;
+               }
+       }
+       for (i = 0, n = aje->h; i < len; n = n->next, i++) {
+               if (!used[i])
+                       list_append(res, n->data);
+       }
+       return res;
+}
+
+static sql_rel *
+remove_blocking_selects( mvc *sql, sql_rel *p, sql_rel *rel)
+{
+       if (rel_is_ref(rel))
+               return rel;
+
+       switch(rel->op) {
+       case op_select:
+               if (p) {
+                       sql_rel *l = rel->l;
+                       if (is_single(rel) || l->op != op_join)
+                               return rel;
+                       if (!list_empty(rel->exps)) {
+                               p->exps = list_join(p->exps, rel->exps);
+                               rel->exps = NULL;
+                       }
+                       if (list_empty(rel->exps)) {
+                               sql_rel *l = rel->l;
+                               rel->l = NULL;
+                               rel_destroy(sql, rel);
+                               return remove_blocking_selects( sql, p, l);
+                       }
+               }
+               return rel;
+       case op_join:
+               rel->l = remove_blocking_selects(sql, rel, rel->l);
+               rel->r = remove_blocking_selects(sql, rel, rel->r);
+               return rel;
+       default:
+               return rel;
+       }
+}
+
+static void
+get_relations(visitor *v, sql_rel *rel, list *rels)
+{
+       if (list_empty(rel->attr) && !rel_is_ref(rel) && rel->op == op_join && 
rel->exps == NULL && !is_single(rel)) {
+               sql_rel *l = rel->l;
+               sql_rel *r = rel->r;
+
+               get_relations(v, l, rels);
+               get_relations(v, r, rels);
+               rel->l = NULL;
+               rel->r = NULL;
+               rel_destroy(v->sql, rel);
+       } else {
+               append(rels, rel);
+       }
+}
+
+static sql_rel *
+rel_estimate(visitor *v, sql_rel *rel)
+{
+       /* Don't prune updates as pruning will possibly result in removing the 
joins which therefore cannot be used for constraint checking */
+       sql_rel *l = rel->l, *r = rel->r;
+
+       if (is_join(rel->op) || is_semi(rel->op)) {
+               rel->l = rel_estimate(v, rel->l);
+               rel->r = rel_estimate(v, rel->r);
+       }
+       if (is_join(rel->op))
+               rel->exps = exps_exp_visitor_bottomup(v, rel, rel->exps, 0, 
&rel_propagate_statistics, false);
+
+       switch (rel->op) {
+       case op_join:
+       case op_left:
+       case op_right:
+       case op_full:
+       {
+               /* propagate row count */
+               BUN lv = get_rel_count(l), rv = get_rel_count(r), 
r_uniques_estimate = BUN_MAX, join_idx_estimate = BUN_MAX;
+
+               //assert (lv < 1000000000 && rv < 1000000000);
+               if (!list_empty(rel->exps) && !is_single(rel) && rel->op == 
op_join) {
+                       for (node *n = rel->exps->h ; n ; n = n->next) {
+                               sql_exp *e = n->data, *el = e->l, *er = e->r;
+                               BUN uniques_estimate = BUN_MAX;
+
+                               if (find_prop(e->p, PROP_JOINIDX)) {
+                                       prop *lsp = find_prop(l->p, 
PROP_SELECTIVITY), *rsp = find_prop(r->p, PROP_SELECTIVITY);
+                                       dbl ls = lsp && is_join(l->op) ? 
lsp->value.dval : 1.0;
+                                       dbl rs = rsp && is_join(r->op) ? 
rsp->value.dval : 1.0;
+                                       join_idx_estimate = lv>rv?lv:rv;
+                                       join_idx_estimate = 
(BUN)(join_idx_estimate * ls * rs);
+                                       if (join_idx_estimate < 1)
+                                               join_idx_estimate = 1;
+                                       dbl s = 
((dbl)join_idx_estimate/(lv*rv));
+                                       prop *sp = prop_create(v->sql->sa, 
PROP_SELECTIVITY, (prop *) e->p);
+                                       sp->value.dval = s;
+                                       e->p = sp;
+                               } else if (e->type == e_cmp && e->flag == 
cmp_equal) {
+                                       /* if one of the sides is unique, the 
cardinality will be at most the cardinality of the other side */
+                                       if (!is_semantics(e) || !has_nil(el) || 
!has_nil(er)) {
+                                               BUN lu = lv, ru = rv;
+                                               prop *p = NULL;
+                                               if ((p = find_prop(el->p, 
PROP_NUNIQUES)))
+                                                       lu = (BUN) 
p->value.dval;
+                                               if ((p = find_prop(er->p, 
PROP_NUNIQUES)))
+                                                       ru = (BUN) 
p->value.dval;
+                                               if (is_unique(el) || lu > lv) {
+                                                       BUN ncount = 
(is_right(rel->op) || is_full(rel->op) || !lv || lu < lv) ? MAX(lv, rv) : 
rv/(lu/lv);
+                                                       if (ncount == 0)
+                                                               ncount = 
MAX(lv, rv);
+                                                       uniques_estimate = 
MIN(uniques_estimate, ncount);
+                                               } else if (is_unique(er) || ru 
> rv) {
+                                                       BUN ncount = 
(is_left(rel->op) || is_full(rel->op) || !rv || ru < rv) ? MAX(lv, rv) : 
lv/(ru/rv);
+                                                       if (ncount == 0)
+                                                               ncount = 
MAX(lv, rv);
+                                                       uniques_estimate = 
MIN(uniques_estimate, ncount);
+                                               }
+                                               if (uniques_estimate < BUN_MAX) 
{
+                                                       if (uniques_estimate < 
r_uniques_estimate)
+                                                               
r_uniques_estimate = uniques_estimate;
+                                                       dbl s = 
((dbl)uniques_estimate/(lv*rv));
+                                                       prop *sp = 
prop_create(v->sql->sa, PROP_SELECTIVITY, (prop *) e->p);
+                                                       sp->value.dval = s;
+                                                       e->p = sp;
+                                               } else {
+                                                       dbl u = (dbl)MAX(lu, 
ru);
+                                                       dbl s = u/(lv*rv);
+                                                       //dbl s = 1/u;
+                                                       prop *sp = 
prop_create(v->sql->sa, PROP_SELECTIVITY, (prop *) e->p);
+                                                       sp->value.dval = s;
+                                                       e->p = sp;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if (is_single(rel) || is_left(rel->op)) {
+                       set_count_prop(v->sql->sa, rel, lv);
+               } else if (is_right(rel->op)) {
+                       set_count_prop(v->sql->sa, rel, rv);
+               } else if (is_full(rel->op)) {
+                       set_count_prop(v->sql->sa, rel, MAX(lv,rv));
+               } else if (join_idx_estimate < BUN_MAX) {
+                       set_count_prop(v->sql->sa, rel, join_idx_estimate);
+               } else if (r_uniques_estimate < BUN_MAX) {
+                       set_count_prop(v->sql->sa, rel, r_uniques_estimate);
+               } else if (list_length(rel->exps) == 1 && 
(exp_is_false(rel->exps->h->data) || exp_is_null(rel->exps->h->data))) {
+                       /* corner cases for outer joins */
+                       if (is_left(rel->op)) {
+                               set_count_prop(v->sql->sa, rel, lv);
+                       } else if (is_right(rel->op)) {
+                               set_count_prop(v->sql->sa, rel, rv);
+                       } else if (is_full(rel->op) && lv != BUN_NONE && rv != 
BUN_NONE) {
+                               set_count_prop(v->sql->sa, rel, (rv > (BUN_MAX 
- lv)) ? BUN_MAX : (lv + rv)); /* overflow check */
+                       } else if (lv != BUN_NONE && rv != BUN_NONE) {
+                               set_count_prop(v->sql->sa, rel, 0);
+                       }
+               } else if (lv == 0) {
+                       set_count_prop(v->sql->sa, rel, (is_right(rel->op) || 
is_full(rel->op)) ? rv : 0);
+               } else if (rv == 0) {
+                       set_count_prop(v->sql->sa, rel, (is_left(rel->op) || 
is_full(rel->op)) ? lv : 0);
+               } else if (lv != BUN_NONE && rv != BUN_NONE) {
+                       dbl sel = 1.0;
+                       if (!list_empty(rel->exps)) {
+                               for (node *n = rel->exps->h ; n ; n = n->next) {
+                                       sql_exp *e = n->data;
+                                       prop *sp = NULL;
+                                       if ((sp = find_prop(e->p, 
PROP_SELECTIVITY)) == NULL) {
+                                               dbl s = 
exp_estimate_selectivity(v->sql, e, rel);
+                                               /* store selectivity on 
predicate for later use */
+                                               sp = prop_create(v->sql->sa, 
PROP_SELECTIVITY, e->p);
+                                               sp->value.dval = s;
+                                               e->p = sp;
+                                       }
+                                       sel *= sp->value.dval;
+                               }
+                       }
+                       dbl est = (dbl)lv * (dbl)rv * sel;
+                       if (est <= 1)
+                               est = 2;
+                       set_count_prop(v->sql->sa, rel, est > (dbl)BUN_MAX ? 
BUN_MAX : (BUN)est);
+                       prop *sp = NULL;
+                       if ((sp = find_prop(rel->p, PROP_SELECTIVITY)) == NULL) 
{
+                               /* store selectivity on predicate for later use 
*/
+                               rel->p = sp = prop_create(v->sql->sa, 
PROP_SELECTIVITY, rel->p);
+                               sp->value.dval = sel;
+                       }
+               }
+       }       break;
+       case op_anti:
+               set_count_prop(v->sql->sa, rel, get_rel_count(l));
+               break;
+       case op_semi:
+               if (list_length(rel->exps) == 1 && 
(exp_is_false(rel->exps->h->data) || exp_is_null(rel->exps->h->data))) {
+                       set_count_prop(v->sql->sa, rel, 0);
+               } else {
+                       if (!list_empty(rel->exps) && !is_single(rel)) {
+                               BUN cnt = get_rel_count(l);
+                               dbl sel = 1.0;
+                               for (node *n = rel->exps->h ; n ; n = n->next) {
+                                       sql_exp *e = n->data;
+                                       dbl s = 
exp_estimate_selectivity(v->sql, e, rel);
+                                       /* store selectivity on predicate for 
later use */
+                                       prop *sp = prop_create(v->sql->sa, 
PROP_SELECTIVITY, (prop *) e->p);
+                                       sp->value.dval = s;
+                                       e->p = sp;
+                                       sel *= s;
+                               }
+                               BUN est = cnt == 0 ? 0 : (BUN)((dbl)cnt * sel);
+                               if (est > cnt)
+                                       est = cnt;
+                               if (est <= 1 && cnt > 0)
+                                       est = 2;
+                               set_count_prop(v->sql->sa, rel, est);
+                               prop *sp = NULL;
+                               if ((sp = find_prop(rel->p, PROP_SELECTIVITY)) 
== NULL) {
+                                       /* store selectivity on predicate for 
later use */
+                                       rel->p = sp = prop_create(v->sql->sa, 
PROP_SELECTIVITY, rel->p);
+                                       sp->value.dval = sel;
+                               }
+                       } else {
+                               set_count_prop(v->sql->sa, rel, 
get_rel_count(l));
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+       return rel;
+}
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to