Changeset: 3f6c10b09d8a for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3f6c10b09d8a
Modified Files:
        sql/server/rel_optimizer.c
        
sql/test/BugTracker-2016/Tests/CREATE_INDEX_breaks_table_queries.Bug-4053.stable.out
        sql/test/Tests/keys.sql
        sql/test/Tests/keys.stable.out
Branch: Nov2019
Log Message:

Added rel_distinct_aggregate_on_unique_values optimizer where transforms 
aggr(distinct unique_val) -> aggr(unique_val)


diffs (218 lines):

diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -2476,6 +2476,51 @@ rel_is_join_on_pkey( sql_rel *rel )
        return 0;
 }
 
+/* if all arguments to a distinct aggregate are unique, remove 'distinct' 
property */
+static sql_rel *
+rel_distinct_aggregate_on_unique_values(int *changes, mvc *sql, sql_rel *rel)
+{
+       sql_rel *l = (sql_rel*) rel->l;
+
+       (void) sql;
+       if (rel->op == op_groupby && (!l || is_base(l->op))) {
+               for (node *n = rel->exps->h; n; n = n->next) {
+                       sql_exp *exp = (sql_exp*) n->data;
+
+                       if (exp->type == e_aggr && need_distinct(exp)) {
+                               bool all_unique = true;
+
+                               for (node *m = ((list*)exp->l)->h; m && 
all_unique; m = m->next) {
+                                       sql_exp *arg = (sql_exp*) m->data;
+
+                                       if (arg->card == CARD_ATOM) /* 
constants are always unique */
+                                               continue;
+                                       else if (arg->type == e_column) {
+                                               fcmp cmp = (fcmp)&kc_column_cmp;
+                                               sql_column *c = 
exp_find_column(rel, arg, -2);
+
+                                               if (c) {
+                                                       /* column is the only 
primary key column of its table */
+                                                       if (find_prop(arg->p, 
PROP_HASHCOL) && c->t->pkey && list_find(c->t->pkey->k.columns, c, cmp) != NULL 
&& list_length(c->t->pkey->k.columns) == 1)
+                                                               continue;
+                                                       else if (c->unique == 
1) /* column has unique constraint */
+                                                               continue;
+                                                       else
+                                                               all_unique = 
false;
+                                               } else
+                                                       all_unique = false;
+                                       } else
+                                               all_unique = false;
+                               }
+                               if (all_unique) {
+                                       set_nodistinct(exp);
+                                       *changes = 1;
+                               }
+                       }
+               }
+       }
+       return rel;
+}
 
 static sql_rel *
 rel_distinct_project2groupby(int *changes, mvc *sql, sql_rel *rel)
@@ -9005,6 +9050,7 @@ optimize_rel(mvc *sql, sql_rel *rel, int
                        rel = rel_case_fixup(&changes, sql, rel, 1);
                        if (value_based_opt)
                                rel = rewrite(sql, rel, &rel_simplify_math, 
&changes);
+                       rel = rewrite(sql, rel, 
&rel_distinct_aggregate_on_unique_values, &changes);
                        rel = rewrite(sql, rel, &rel_distinct_project2groupby, 
&changes);
                }
        }
diff --git 
a/sql/test/BugTracker-2016/Tests/CREATE_INDEX_breaks_table_queries.Bug-4053.stable.out
 
b/sql/test/BugTracker-2016/Tests/CREATE_INDEX_breaks_table_queries.Bug-4053.stable.out
--- 
a/sql/test/BugTracker-2016/Tests/CREATE_INDEX_breaks_table_queries.Bug-4053.stable.out
+++ 
b/sql/test/BugTracker-2016/Tests/CREATE_INDEX_breaks_table_queries.Bug-4053.stable.out
@@ -84,20 +84,20 @@ stdout of test 'CREATE_INDEX_breaks_tabl
 % int, bigint, int,    int,    timestamp,      smallint,       smallint,       
clob,   clob,   clob,   clob,   int,    clob,   clob,   clob,   clob,   clob,   
clob,   clob,   clob,   clob,   clob,   clob,   clob,   clob,   clob,   clob,   
clob,   clob,   clob,   clob,   clob,   clob,   double, double, double, double, 
double, double, double, double, double, double, double, double, double, int,    
boolean,        bigint, int,    int,    int # type
 % 1,   1,      1,      1,      26,     1,      1,      0,      0,      0,      
0,      1,      0,      0,      0,      0,      0,      0,      0,      0,      
0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      
0,      0,      0,      24,     24,     24,     24,     24,     24,     24,     
24,     24,     24,     24,     24,     24,     1,      5,      1,      1,      
1,      1 # length
 #SELECT count(distinct "anno_mese") FROM "sys"."farmap_movimento";
-% sys.L4 # table_name
-% L3 # name
+% sys.L2 # table_name
+% L2 # name
 % bigint # type
 % 1 # length
 [ 0    ]
 #SELECT count(distinct "articolo_id") FROM "sys"."farmap_movimento";
-% sys.L4 # table_name
-% L3 # name
+% .L2 # table_name
+% L2 # name
 % bigint # type
 % 1 # length
 [ 0    ]
 #SELECT count(distinct "farmacia_id") FROM "sys"."farmap_movimento";
-% sys.L4 # table_name
-% L3 # name
+% .L2 # table_name
+% L2 # name
 % bigint # type
 % 1 # length
 [ 0    ]
diff --git a/sql/test/Tests/keys.sql b/sql/test/Tests/keys.sql
--- a/sql/test/Tests/keys.sql
+++ b/sql/test/Tests/keys.sql
@@ -1,3 +1,4 @@
+START TRANSACTION;
 CREATE TABLE allnewtriples (id integer NOT NULL, subject integer NOT
 NULL, predicate integer NOT NULL, "object" integer NOT NULL, explicit
 boolean NOT NULL, CONSTRAINT unique_key UNIQUE(subject, predicate, "object"));
@@ -9,3 +10,18 @@ SELECT idxs.name, idxs."type", keys.name
 FROM idxs LEFT JOIN keys on idxs.name = keys.name;
 SELECT idxs.name, idxs."type", keys.name, keys."type" 
 FROM idxs JOIN keys on idxs.name = keys.name;
+
+/* test elimination of distinct restriction on aggregates */
+create table dummyme (a int primary key, b int);
+insert into dummyme values (1,1), (2,1), (3,1);
+
+/* eliminated */
+plan select count(distinct a) from dummyme;
+plan select count(distinct a) from dummyme group by b;
+
+/* not eliminated */
+plan select count(distinct b) from dummyme;
+plan select count(distinct a + 1) from dummyme;
+plan select count(distinct a + b) from dummyme;
+plan select count(distinct abs(a)) from dummyme;
+ROLLBACK;
diff --git a/sql/test/Tests/keys.stable.out b/sql/test/Tests/keys.stable.out
--- a/sql/test/Tests/keys.stable.out
+++ b/sql/test/Tests/keys.stable.out
@@ -119,6 +119,94 @@ stdout of test 'keys` in directory 'sql/
 [ "pg_pkey_id_file_id",        0,      "pg_pkey_id_file_id",   0       ]
 [ "pg_fkey_file_id",   1,      "pg_fkey_file_id",      2       ]
 [ "unique_key",        0,      "unique_key",   1       ]
+#create table dummyme (a int primary key, b int);
+#insert into dummyme values (1,1), (2,1), (3,1);
+[ 3    ]
+#plan select count(distinct a) from dummyme;
+% .plan # table_name
+% rel # name
+% clob # type
+% 85 # length
+project (
+| group by (
+| | table(sys.dummyme) [ "dummyme"."a" NOT NULL HASHCOL  ] COUNT 
+| ) [  ] [ sys.count no nil ("dummyme"."a" NOT NULL HASHCOL ) NOT NULL as 
"L2"."L2" ]
+) [ "L2"."L2" NOT NULL ]
+#plan select count(distinct a) from dummyme group by b;
+% .plan # table_name
+% rel # name
+% clob # type
+% 113 # length
+project (
+| group by (
+| | table(sys.dummyme) [ "dummyme"."a" NOT NULL HASHCOL , "dummyme"."b" ] 
COUNT 
+| ) [ "dummyme"."b" ] [ "dummyme"."b", sys.count no nil ("dummyme"."a" NOT 
NULL HASHCOL ) NOT NULL as "L1"."L1" ]
+) [ "L1"."L1" NOT NULL ]
+#plan select count(distinct b) from dummyme;
+% .plan # table_name
+% rel # name
+% clob # type
+% 54 # length
+project (
+| group by (
+| | group by (
+| | | table(sys.dummyme) [ "dummyme"."b" ] COUNT 
+| | ) [ "dummyme"."b" as "L3"."L3" ] [ "L3"."L3" ]
+| ) [  ] [ sys.count no nil ("L3"."L3") as "L2"."L2" ]
+) [ "L2"."L2" ]
+#plan select count(distinct a + 1) from dummyme;
+% .plan # table_name
+% rel # name
+% clob # type
+% 148 # length
+project (
+| group by (
+| | group by (
+| | | project (
+| | | | project (
+| | | | | table(sys.dummyme) [ "dummyme"."a" NOT NULL HASHCOL  ] COUNT 
+| | | | ) [ "dummyme"."a" NOT NULL HASHCOL , bigint["dummyme"."a" NOT NULL 
HASHCOL ] as "L4"."L4", sys.sql_add("L4"."L4", bigint "1") as "L5"."L5" ]
+| | | ) [ "L5"."L5" ]
+| | ) [ "L5"."L5" as "L7"."L7" ] [ "L7"."L7" ]
+| ) [  ] [ sys.count no nil ("L7"."L7") as "L2"."L2" ]
+) [ "L2"."L2" ]
+#plan select count(distinct a + b) from dummyme;
+% .plan # table_name
+% rel # name
+% clob # type
+% 198 # length
+project (
+| group by (
+| | group by (
+| | | project (
+| | | | project (
+| | | | | table(sys.dummyme) [ "dummyme"."a" NOT NULL HASHCOL , "dummyme"."b" 
] COUNT 
+| | | | ) [ "dummyme"."a" NOT NULL HASHCOL , "dummyme"."b", 
bigint["dummyme"."a" NOT NULL HASHCOL ] as "L4"."L4", bigint["dummyme"."b"] as 
"L5"."L5", sys.sql_add("L4"."L4", "L5"."L5") as "L6"."L6" ]
+| | | ) [ "L6"."L6" ]
+| | ) [ "L6"."L6" as "L10"."L10" ] [ "L10"."L10" ]
+| ) [  ] [ sys.count no nil ("L10"."L10") as "L2"."L2" ]
+) [ "L2"."L2" ]
+#plan select count(distinct abs(a)) from dummyme;
+% .plan # table_name
+% rel # name
+% clob # type
+% 100 # length
+project (
+| group by (
+| | group by (
+| | | project (
+| | | | project (
+| | | | | table(sys.dummyme) [ "dummyme"."a" NOT NULL HASHCOL  ] COUNT 
+| | | | ) [ "dummyme"."a" NOT NULL HASHCOL , sys.abs("dummyme"."a" NOT NULL 
HASHCOL ) as "L4"."L4" ]
+| | | ) [ "L4"."L4" ]
+| | ) [ "L4"."L4" as "L6"."L6" ] [ "L6"."L6" ]
+| ) [  ] [ sys.count no nil ("L6"."L6") as "L2"."L2" ]
+) [ "L2"."L2" ]
+#ROLLBACK;
+
+# 15:20:15 >  
+# 15:20:15 >  "Done."
+# 15:20:15 >  
 
 # 16:23:54 >  
 # 16:23:54 >  "Done."
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to