Changeset: 36e282f14df5 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/36e282f14df5
Modified Files:
        sql/backends/monet5/rel_bin.c
        sql/backends/monet5/rel_physical.c
        sql/backends/monet5/rel_util.c
        sql/backends/monet5/sql_pp_statement.c
        sql/include/sql_relation.h
        sql/server/rel_dump.c
        sql/server/rel_exp.c
        sql/server/rel_optimize_join.c
        sql/server/rel_statistics.c
Branch: default
Log Message:

improved computation of join-costs and cardinality estimation


diffs (truncated from 434 to 300 lines):

diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c
--- a/sql/backends/monet5/rel_bin.c
+++ b/sql/backends/monet5/rel_bin.c
@@ -8279,7 +8279,7 @@ exp_remap(sql_exp *le, sql_exp *re, list
        case e_column:
                if (exp_pair_match(remapped, le->nid, re->nid))
                        return 0;
-               break;
+               return -1;
        case e_convert:
                ll = le->r;
                rl = re->r;
@@ -8385,8 +8385,7 @@ deduplicate_refs(mvc *sql, allocator *ta
        for(node *n = refs->h; n; n = n->next) {
                sql_rel *or = n->data, *nr = or;
                prop *op = find_prop(or->p, PROP_HASH);
-               if (or->op == op_buildhash &&
-                               op && op->value.lval) {
+               if (or->op == op_buildhash && op && op->value.lval) {
                        BUN h = op->value.lval;
                        for(node *m = prefs->h; m; m = m->next->next) {
                                sql_rel *ir = m->data;
diff --git a/sql/backends/monet5/rel_physical.c 
b/sql/backends/monet5/rel_physical.c
--- a/sql/backends/monet5/rel_physical.c
+++ b/sql/backends/monet5/rel_physical.c
@@ -504,8 +504,10 @@ find_cmp_exps(list **exps_hsh, list **ex
                        sql_exp *ne = NULL;
                        if ((ne = rel_find_exp(rel_hsh, e->r)) != NULL) {
                                sql_exp *er = e->r;
+                               /*
                                if (is_unique(ne))
                                        set_unique(er);
+                                       */
                                if (any)
                                        set_any(er);
                                if (semantic)
@@ -516,8 +518,10 @@ find_cmp_exps(list **exps_hsh, list **ex
                            ne = rel_find_exp(rel_hsh, e->l);
                                assert(ne);
                                sql_exp *el = e->l;
+                               /*
                                if (is_unique(ne))
                                        set_unique(el);
+                                       */
                                if (any)
                                        set_any(el);
                                if (semantic)
diff --git a/sql/backends/monet5/rel_util.c b/sql/backends/monet5/rel_util.c
--- a/sql/backends/monet5/rel_util.c
+++ b/sql/backends/monet5/rel_util.c
@@ -89,14 +89,18 @@ void
 split_join_exps(sql_rel *rel, list *joinable, list *not_joinable, bool anti, 
bool eqonly)
 {
        if (!list_empty(rel->exps)) {
+               bool done = false;
                for (node *n = rel->exps->h; n; n = n->next) {
                        sql_exp *e = n->data;
 
                        /* eqonly -
                         *   TRUE: only handle equi-join expressions, e.g. in 
case of pipeline hash join
                         *   FALSE: we can (also) handle thetajoins, rangejoins 
and filter joins (like) */
-                       if (can_join_exp(rel, e, anti) && (!eqonly || 
(is_equi_exp_(e) && !exp_is_atom(e->r) && !exp_is_atom(e->l)))) {
+                       if (!done && (can_join_exp(rel, e, anti) && (!eqonly || 
(is_equi_exp_(e) && !exp_is_atom(e->r) && !exp_is_atom(e->l))))) {
                                append(joinable, e);
+                               sql_exp *el = e->l, *er = e->r;
+                               if (eqonly && is_innerjoin(rel->op) && 
(is_unique(el) || is_unique(er)))
+                                       done = true;
                        } else {
                                append(not_joinable, e);
                        }
diff --git a/sql/backends/monet5/sql_pp_statement.c 
b/sql/backends/monet5/sql_pp_statement.c
--- a/sql/backends/monet5/sql_pp_statement.c
+++ b/sql/backends/monet5/sql_pp_statement.c
@@ -565,6 +565,11 @@ stmt_oahash_probe(backend *be, stmt *key
                q = pushArgument(be->mb, q, getArg(prev->q, 0));
                q = pushArgument(be->mb, q, getArg(prev->q, 1));
        }
+       /*
+       sql_subtype *htype = tail_type(rhs_ht);
+       sql_subtype *ptype = tail_type(key);
+       assert(subtype_cmp(htype, ptype) == 0);
+       */
        q = pushArgument(be->mb, q, rhs_ht->nr);
        if (single) {
                assert(freq);
diff --git a/sql/include/sql_relation.h b/sql/include/sql_relation.h
--- a/sql/include/sql_relation.h
+++ b/sql/include/sql_relation.h
@@ -351,11 +351,12 @@ typedef struct relation {
                                 */
        int nrcols;     /* nr of cols */
        unsigned int
-        flag:16,
         card:2,        /* 0, 1 (row), 2 aggr, 3 */
         dependent:1,   /* dependent join */
         distinct:1,
         fv_distinct:1, /* set during general unnest */
+        lunique:1,             /* left side of join unique */
+        runique:1,             /* right side of join unique */
         processed:1,   /* fully processed or still in the process of building 
*/
         outer:1,       /* used as outer (ungrouped) */
         grouped:1,     /* groupby processed all the group by exps */
@@ -374,6 +375,7 @@ typedef struct relation {
         * Used by rewriters at rel_unnest, rel_optimizer and rel_distribute so 
a relation is not modified twice
         * The list is kept at rel_optimizer_private.h Please update it 
accordingly
         */
+       uint16_t flag;
        uint16_t used;
        uint16_t nr_outers;
        int opt;
diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c
--- a/sql/server/rel_dump.c
+++ b/sql/server/rel_dump.c
@@ -381,7 +381,7 @@ exp_print(mvc *sql, stream *fout, sql_ex
                        mnstr_printf(fout, " NULLS LAST");
                if (e->type != e_atom && e->type != e_cmp && !has_nil(e))
                        mnstr_printf(fout, " NOT NULL");
-               if (e->type != e_atom && e->type != e_cmp && is_unique(e))
+               if (e->type != e_atom && (sql->show_all_details || e->type != 
e_cmp) && is_unique(e))
                        mnstr_printf(fout, " UNIQUE");
                /* don't show properties on value lists */
                if (decorate && e->p && e->type != e_atom && !exp_is_atom(e)) {
diff --git a/sql/server/rel_exp.c b/sql/server/rel_exp.c
--- a/sql/server/rel_exp.c
+++ b/sql/server/rel_exp.c
@@ -176,7 +176,7 @@ exp_compare(allocator *sa, sql_exp *l, s
        e->l = l;
        e->r = r;
        e->flag = cmptype;
-       if (cmptype == cmp_equal) {
+       if (cmptype == cmp_equal && r->card <= CARD_AGGR) {
                prop *p = e->p = prop_create(sa, PROP_NUNIQUES, (prop *) e->p);
                p->value.dval = 1;
        }
@@ -197,7 +197,7 @@ exp_compare2(allocator *sa, sql_exp *l, 
        e->r = r;
        e->f = f;
        e->flag = cmptype;
-       if (cmptype == cmp_equal) {
+       if (cmptype == cmp_equal && r->card <= CARD_AGGR) {
                prop *p = e->p = prop_create(sa, PROP_NUNIQUES, (prop *) e->p);
                p->value.dval = 1;
        }
@@ -4419,6 +4419,10 @@ exp_estimate_selectivity(mvc *sql, sql_e
                        case cmp_lt:
                        case cmp_lte:
                                sel = 0.50;
+                               /*
+                               if (e->f)
+                                       sel = 0.10;
+                                       */
                                break;
                        case cmp_in:
                        case cmp_notin: {
diff --git a/sql/server/rel_optimize_join.c b/sql/server/rel_optimize_join.c
--- a/sql/server/rel_optimize_join.c
+++ b/sql/server/rel_optimize_join.c
@@ -115,12 +115,14 @@ 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:
@@ -139,8 +141,8 @@ rel_estimate(visitor *v, sql_rel *rel)
 
                                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;
+                                       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)
@@ -152,7 +154,7 @@ rel_estimate(visitor *v, sql_rel *rel)
                                } 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;
+                                               BUN lu = 1, ru = 1; /* 
initialize with worst case */
                                                prop *p = NULL;
                                                if ((p = find_prop(el->p, 
PROP_NUNIQUES)))
                                                        lu = (BUN) 
p->value.dval;
@@ -177,9 +179,11 @@ rel_estimate(visitor *v, sql_rel *rel)
                                                        sp->value.dval = s;
                                                        e->p = sp;
                                                } else {
-                                                       dbl u = (dbl)MAX(lu, 
ru);
+                                                       dbl mfl = (dbl)lv/lu;
+                                                       dbl mfr = (dbl)rv/ru;
+                                                       dbl mf = MIN(lv/mfl, 
rv/mfr);
+                                                       dbl u = mf * mfl * mfr;
                                                        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;
@@ -407,7 +411,7 @@ extern void _exps_print(mvc *sql, list *
 static prop *
 exp_selectivity(visitor *v, sql_exp *e, sql_rel *l, sql_rel *r, prop *p)
 {
-       BUN lv = get_rel_count(l), rv = get_rel_count(r), r_uniques_estimate = 
BUN_MAX, join_idx_estimate = BUN_MAX;
+       BUN lv = get_rel_count(l), rv = get_rel_count(r), join_idx_estimate = 
BUN_MAX;
        sql_exp *el = e->l, *er = e->r;
        BUN uniques_estimate = BUN_MAX;
        prop *jip = find_prop(e->p, PROP_JOINIDX);
@@ -436,30 +440,32 @@ exp_selectivity(visitor *v, sql_exp *e, 
        } 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, nlv = lv, nrv = rv;
+                       BUN lu = 1, ru = 1; /* initialize with worst case */
                        prop *up = NULL;
                        if (el->type == e_column && (is_select(l->op) || 
is_basetable(l->op)))
                                el = rel_find_exp(l, el);
                        if ((up = find_prop(el->p, PROP_NUNIQUES)))
-                               lu = (BUN) up->value.dval;
+                               lu = MIN((BUN) up->value.dval, lv);
                        if (er->type == e_column && (is_select(r->op) || 
is_basetable(r->op)))
                                er = rel_find_exp(r, er);
                        if ((up = find_prop(er->p, PROP_NUNIQUES)))
-                               ru = (BUN) up->value.dval;
-                       if (is_unique(el) || (is_unique(er) && runique)) {
+                               ru = MIN((BUN) up->value.dval, rv);
+                       if (is_unique(el) || (is_unique(er) && runique))
                                uniques_estimate = MIN(uniques_estimate, 
MAX(lv, rv));
-                       }
+                       if (is_unique(el) && is_unique(er) && runique)
+                               uniques_estimate = MIN(lu, ru);
                        if (uniques_estimate != BUN_MAX) {
-                               if (uniques_estimate < r_uniques_estimate)
-                                       r_uniques_estimate = uniques_estimate;
                                dbl s = ((dbl)uniques_estimate/(lv*rv));
                                if (!p)
                                        p = prop_create(v->sql->sa, 
PROP_SELECTIVITY, (prop *) e->p);
                                p->value.dval = s;
                                e->p = p;
                        } else {
-                               dbl u = ((dbl)lu*ru) / (nlv*nrv);
-                               dbl s = 1/u;
+                               dbl mfl = (dbl)lv/lu;
+                               dbl mfr = (dbl)rv/ru;
+                               dbl mf = MIN(lv/mfl, rv/mfr);
+                               dbl u = mf * mfl * mfr;
+                               dbl s = u/(lv*rv);
                                if (!p)
                                        p = prop_create(v->sql->sa, 
PROP_SELECTIVITY, (prop *) e->p);
                                p->value.dval = s;
@@ -477,6 +483,39 @@ exp_selectivity(visitor *v, sql_exp *e, 
        return p;
 }
 
+static sql_exp *
+find_unique(sql_exp *e, sql_rel *rel)
+{
+       if (is_select(rel->op) || is_basetable(rel->op))
+               return rel_find_exp(rel, e);
+       if (is_join(rel->op)) {
+               if (rel->lunique)
+                       return find_unique(e, rel->l);
+               if (rel->runique)
+                       return find_unique(e, rel->r);
+       }
+       return NULL;
+}
+
+static void
+exp_set_uniques(sql_exp *e, sql_rel *l, sql_rel *r)
+{
+       if (e->type == e_cmp) {
+               if (e->flag == cmp_equal || e->flag == cmp_notequal) {
+                       exp_set_uniques(e->l, l, r);
+                       exp_set_uniques(e->r, l, r);
+               }
+       } else if (e->type == e_column) {
+               sql_exp *be = find_unique(e, l);
+               if (!be)
+                       be = find_unique(e, r);
+               if (be && is_unique(be))
+                       set_unique(e);
+               else
+                       set_not_unique(e);
+       }
+}
+
 static int VERBOSE = 0;
 
 static dbl
@@ -487,6 +526,7 @@ exp_cost(visitor *v, sql_exp *e, ulng ma
 
        if (!l || !r)
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to