Changeset: 2cb9164b70c3 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/2cb9164b70c3
Modified Files:
        sql/include/sql_relation.h
        sql/server/rel_optimize_sel.c
Branch: default
Log Message:

implemented next (bits) of join reordering.
Also remove any redundant join expressions (left overs from transitivity)


diffs (truncated from 332 to 300 lines):

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
@@ -38,6 +38,7 @@ typedef struct prop {
                dbl dval; /* property with estimate */
                void *pval; /* property value */
        } value;
+       list *exps;
        struct prop *p; /* some relations may have many properties, which are 
kept in a chain list */
 } prop;
 
diff --git a/sql/server/rel_optimize_sel.c b/sql/server/rel_optimize_sel.c
--- a/sql/server/rel_optimize_sel.c
+++ b/sql/server/rel_optimize_sel.c
@@ -1609,6 +1609,7 @@ find_fk( mvc *sql, list *rels, list *exp
                                prop *p;
                                node *n;
                                sql_exp *t = NULL, *i = NULL;
+                               list *jexps = sa_list(sql->sa);
 
                                if (list_length(lcols) > 1 || 
!mvc_debug_on(sql, 512)) {
 
@@ -1636,20 +1637,25 @@ find_fk( mvc *sql, list *rels, list *exp
                                        }
 
                                        /* Remove all join expressions */
-                                       for (n = eje->h; n; n = n->next)
+                                       for (n = eje->h; n; n = n->next) {
                                                list_remove_data(exps, NULL, 
n->data);
+                                               append(jexps, n->data);
+                                       }
                                        append(exps, je);
                                        djn->data = je;
                                } else if (swapped) { /* else keep je for 
single column expressions */
                                        je = exp_compare(sql->sa, je->r, je->l, 
cmp_equal);
                                        /* Remove all join expressions */
-                                       for (n = eje->h; n; n = n->next)
+                                       for (n = eje->h; n; n = n->next) {
                                                list_remove_data(exps, NULL, 
n->data);
+                                               append(jexps, n->data);
+                                       }
                                        append(exps, je);
                                        djn->data = je;
                                }
                                je->p = p = prop_create(sql->sa, PROP_JOINIDX, 
je->p);
                                p->value.pval = idx;
+                               p->exps = jexps;
                        }
                }
        }
@@ -3115,21 +3121,13 @@ struct jo_pair {
        list *exps;
 };
 
-static sql_rel *
-order_joins_bushy( visitor *v, list *rels, list *exps)
+
+static void
+mark_join_sides(allocator *ta, list *rels, list *exps,
+               ulng *Max, sql_rel ***Rels_a, uint16_t **R1, uint16_t **R2, int 
**R3)
 {
-       unsigned int rsingle;
-
-       /* split joins into n_m joins and filters (ie others with 1 side 
unique's (pkey/ukey etc) */
-       //for (node *n = exps->h; n; n = n->next) {
-               //sql_exp *je = n->data;
-               //if (find_prop(je->p, PROP_JOINIDX)) {
-                       //printf("join\n");
-               //}
-       //}
-       /* loop of finding join pairs */
-       allocator *ta = MT_thread_getallocator();
        int nr_exps = list_length(exps), nr_rels = list_length(rels), ci = 1;
+
        sql_rel **rels_a = SA_NEW_ARRAY(ta, sql_rel*, nr_rels+1); /* don't use 
slot 0 */
        rels_a[0] = NULL;
        ulng max = 0;
@@ -3144,7 +3142,6 @@ order_joins_bushy( visitor *v, list *rel
        uint16_t *r2 = SA_NEW_ARRAY(ta, uint16_t, nr_exps);
        /* change r3 into rest list's */
        int *r3 = SA_NEW_ARRAY(ta, int, nr_exps);
-       int *useda = SA_ZNEW_ARRAY(ta, int, nr_exps);
 
        ci = 0;
        for (node *n = exps->h; n; n = n->next, ci++) {
@@ -3166,7 +3163,31 @@ order_joins_bushy( visitor *v, list *rel
                        }
                }
        }
+       *Max = max;
+       *Rels_a = rels_a;
+       *R1 = r1;
+       *R2 = r2;
+       *R3 = r3;
+}
+
+static sql_rel *
+order_joins_bushy( visitor *v, list *rels, list *exps)
+{
+       unsigned int rsingle;
+
+       /* loop of finding join pairs */
+       allocator *ta = MT_thread_getallocator();
+       int nr_exps = list_length(exps), nr_rels = list_length(rels);
+       ulng max = 0;
+       sql_rel **rels_a = NULL;
+       uint16_t *r1, *r2;
+       int *r3;
+
+       mark_join_sides(ta, rels, exps, &max, &rels_a, &r1, &r2, &r3);
+
+
        /* find number of unique pairs */
+       int *useda = SA_ZNEW_ARRAY(ta, int, nr_exps);
        int nr_pairs = unique_pairs(r1, r2, nr_exps, useda);
        struct jo_pair *pairs = SA_ZNEW_ARRAY(ta, struct jo_pair, nr_pairs);
        int used = 0, i = 0;
@@ -3357,6 +3378,195 @@ order_joins_bushy( visitor *v, list *rel
        return top;
 }
 
+static bool
+exp_allready_checked(sql_rel *r, sql_exp *e, list *exps)
+       /* r is join tree,
+        * e is equality join expression, which may overlap with earlier join 
expressions in some transitive way
+        * exps list of all join expressions in the tree r
+        */
+{
+       (void)r;
+       sql_exp *el = e->l, *er = e->r;
+       if (e->type != e_cmp || e->flag != cmp_equal || is_anti(e) || 
is_semantics(e) ||
+               el->type != e_column || er->type != e_column ||
+               list_length(exps) < 2)
+               return false;
+       for (node *n = exps->h; n; n = n->next) {
+               sql_exp *je1 = n->data, *je1l = je1->l, *je1r = je1->r;
+               if (je1->type != e_cmp || je1->flag != cmp_equal || 
is_anti(je1) || is_semantics(je1) ||
+                       je1l->type != e_column || je1r->type != e_column)
+                       continue;
+
+               bool c1 = el->nid == je1l->nid, c2 = el->nid == je1r->nid, c3 = 
er->nid == je1l->nid, c4 = er->nid == je1r->nid;
+               if (c1 || c2 || c3 || c4) {
+                       for (node *m = n->next; m; m = m->next) {
+                               sql_exp *je2 = n->data, *je2l = je2->l, *je2r = 
je2->r;
+                               if (je2->type != e_cmp || je2->flag != 
cmp_equal || is_anti(je2) || is_semantics(je2) ||
+                                       je2l->type != e_column || je2r->type != 
e_column)
+                                       continue;
+                               bool c1 = el->nid == je2l->nid, c2 = el->nid == 
je2r->nid, c3 = er->nid == je2l->nid, c4 = er->nid == je2r->nid;
+                               if (c1 || c2 || c3 || c4) {
+                                       /* todo  check if we have some order of 
el == je1l, je1r == je2l, je2r == er */
+                                       return true;
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+static void
+je_append(list *exps, sql_exp *je)
+{
+       prop *p = find_prop(je->p, PROP_JOINIDX);
+       if (p && p->exps) {
+               list_merge(exps, p->exps, NULL);
+       } else {
+               append(exps, je);
+       }
+}
+
+extern void _rel_print(mvc *sql, sql_rel *rel);
+
+static sql_rel *
+order_joins_bushy2( visitor *v, list *rels, list *exps)
+{
+       /* rels is set of filters relations
+        * exps is set of join expressions
+        * returns join tree
+        */
+
+       int nr_exps = list_length(exps), nr_rels = list_length(rels);
+       /* split joins into n_m joins and filters (ie others with 1 side 
unique's (pkey/ukey etc) */
+       //sql_rel *T = NULL;
+       //for( node *n = rels->h; n; n = n->next) {
+               //_rel_print(v->sql, n->data);
+       //}
+       int nr = 0;
+       for (node *n = exps->h; n; n = n->next) {
+               sql_exp *je = n->data;
+               if (find_prop(je->p, PROP_JOINIDX)) {
+                       //printf("joinidx ");
+                       nr++;
+               }
+               if (je->type == e_cmp && je->flag == cmp_equal) {
+                       sql_exp *le = je->l;
+                       sql_exp *re = je->r;
+                       if (find_prop(le->p, PROP_HASHCOL)) {
+                               //printf("hashcol ");
+                               nr++;
+                       } else if (find_prop(re->p, PROP_HASHCOL)) {
+                               //printf("hashcol ");
+                               nr++;
+                       }
+               }
+               //_exp_print(v->sql, je);
+       }
+       if (nr == list_length(exps)) { /* all pk-fk */
+               allocator *ta = MT_thread_getallocator();
+               ulng max = 0;
+               sql_rel **rels_a = NULL;
+               uint16_t *r1, *r2;
+               int *r3, ci = 1, cur_nr = 1;
+
+               mark_join_sides(ta, rels, exps, &max, &rels_a, &r1, &r2, &r3);
+
+               //printf("all pk fk\n");
+               BUN min = get_rel_count(rels->h->data);
+               sql_rel *cur = rels->h->data;
+               for(node *n = rels->h; n; n = n->next, ci++) {
+                       BUN cnt = get_rel_count(n->data);
+                       if (cnt < min) {
+                               cur = n->data;
+                               min = cnt;
+                               cur_nr = ci;
+                       }
+               }
+               //printf("min %lu ", min);
+               //_rel_print(v->sql, cur);
+               list_remove_data(rels, NULL, cur);
+               list *used_exps = sa_list(ta);
+               while(!list_empty(rels)) {
+                       min = BUN_MAX;
+                       sql_exp *cje = NULL;
+                       for(node *n = exps->h; n; n = n->next) { /* find join 
expr */
+                               sql_exp *je = n->data;
+                               if (r1[je->tmp] == cur_nr || r2[je->tmp] == 
cur_nr) {
+                                       int oside = (r1[je->tmp] == cur_nr) ? 
r2[je->tmp] : r1[je->tmp];
+                                       sql_rel *r = rels_a[oside];
+                                       BUN cnt = get_rel_count(r);
+                                       if (cnt < min) {
+                                               cje = je;
+                                               min = cnt;
+                                       }
+                               }
+                       }
+                       if (cje) {
+                               int oside = (r1[cje->tmp] == cur_nr) ? 
r2[cje->tmp] : r1[cje->tmp];
+                               sql_rel *r = rels_a[oside], *l = cur;
+                               cur = rel_crossproduct(v->sql->sa, l, r, 
op_join);
+                               rel_join_add_exp(v->sql->sa, cur, cje);
+                               je_append(used_exps, cje);
+                               for(int i = 0; i<nr_rels+1; i++) {
+                                       if (rels_a[i] == l || rels_a[i] == r)
+                                               rels_a[i] = cur;
+                               }
+                               for(int i = 0; i<nr_exps; i++) {
+                                       if (r1[i] == oside)
+                                               r1[i] = cur_nr;
+                                       if (r2[i] == oside)
+                                               r2[i] = cur_nr;
+                                       if (r1[i] == r2[i] && r1[i] == cur_nr) {
+                                               sql_exp *je = NULL;
+                                               for (node *n = exps->h; n && 
!je; n = n->next) {
+                                                       sql_exp *e = n->data;
+                                                       if (e->tmp == i)
+                                                               je = e;
+                                               }
+                                               if (je && je != cje) {
+                                                       if 
(!exp_allready_checked(cur, je, used_exps))
+                                                               
rel_join_add_exp(v->sql->sa, cur, je);
+                                                       je_append(used_exps, 
je);
+                                                       list_remove_data(exps, 
NULL, je);
+                                               }
+                                       }
+                               }
+                               list_remove_data(rels, NULL, r);
+                               list_remove_data(exps, NULL, cje);
+                               cur = rel_get_statistics_(v, cur); /* we need 
stats */
+                       } else {
+                               if (!list_empty(exps)) {
+                                       if(!list_empty(rels)) {
+                                               sql_rel *r = rels->h->data;
+                                               list_remove_data(rels, NULL, r);
+                                               cur = 
rel_crossproduct(v->sql->sa, cur, r, op_join);
+                                               cur = rel_get_statistics_(v, 
cur); /* we need stats */
+                                       }
+                               }
+                       }
+                       if (list_empty(exps)) {
+                               while(!list_empty(rels)) {
+                                       sql_rel *r = rels->h->data;
+                                       list_remove_data(rels, NULL, r);
+                                       cur = rel_crossproduct(v->sql->sa, cur, 
r, op_join);
+                                       cur = rel_get_statistics_(v, cur); /* 
we need stats */
+                               }
+                       }
+               }
+               while (!list_empty(exps)) {
+                       sql_exp *je = exps->h->data;
+                       if (!exp_allready_checked(cur, je, used_exps))
+                               rel_join_add_exp(v->sql->sa, cur, je);
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to