Commit 69d4559e authored by Sergey Petrunya's avatar Sergey Petrunya

MWL#17: Table elimination

- Better comments
- More OOM checks

sql/sql_select.cc:
  - Remove garbage code
parent e845f0f8
...@@ -19,6 +19,25 @@ ...@@ -19,6 +19,25 @@
/* /*
OVERVIEW OVERVIEW
This file contains table elimination module. The idea behind table
elimination is as follows: suppose we have a left join
SELECT * FROM t1 LEFT JOIN
(t2 JOIN t3) ON t3.primary_key=t1.col AND
t4.primary_key=t2.col
such that
* columns of the inner tables are not used anywhere ouside the outer join
(not in WHERE, not in GROUP/ORDER BY clause, not in select list etc etc),
* inner side of the outer join is guaranteed to produce at most one matching
record combination for each record combination of outer tables.
then the inner side of the outer join can be removed from the query, as it
will always produce only one record combination (either real or
null-complemented one) and we don't care about what that record combination
is.
MODULE INTERFACE
The module has one entry point - eliminate_tables() function, which one The module has one entry point - eliminate_tables() function, which one
needs to call (once) at some point before the join optimization. needs to call (once) at some point before the join optimization.
eliminate_tables() operates over the JOIN structures. Logically, it eliminate_tables() operates over the JOIN structures. Logically, it
...@@ -38,6 +57,50 @@ ...@@ -38,6 +57,50 @@
by EXPLAIN code to check if the subquery should be shown in EXPLAIN. by EXPLAIN code to check if the subquery should be shown in EXPLAIN.
Table elimination is redone on every PS re-execution. Table elimination is redone on every PS re-execution.
IMPLEMENTATION
As said above, we can remove inner side of an outer join if it is
1. not referred to from any other parts of the query
2. always produces one matching record combination.
We check #1 by doing a recursive descent down the join->join_list while
maintaining a union of used_tables() attribute of all expressions we've seen
"elsewhere". When we encounter an outer join, we check if the bitmap of
tables on its inner side has intersection with tables that are used
elsewhere. No intersection means that inner side of the outer join could
potentially be eliminated.
#2 is checked using a concept of values and modules that indicate
dependencies between them.
We start with
of certain values that functional dependencies between
them. There are two kinds of values:
*/
/*
A value
functional dependencies between two kinds of entities:
*/
class Value_dep;
class Field_value;
class Table_value;
class Module_dep;
class Equality_module;
class Outer_join_module;
class Key_module;
class Table_elimination;
/*
A value.
*/ */
class Value_dep : public Sql_alloc class Value_dep : public Sql_alloc
...@@ -55,13 +118,9 @@ public: ...@@ -55,13 +118,9 @@ public:
Value_dep *next; Value_dep *next;
}; };
class Field_value;
class Table_value;
class Outer_join_module;
class Key_module;
/* /*
A table field. There is only one such object for any tblX.fieldY A table field value. There is exactly only one such object for any tblX.fieldY
- the field epends on its table and equalities - the field epends on its table and equalities
- expressions that use the field are its dependencies - expressions that use the field are its dependencies
*/ */
...@@ -87,7 +146,8 @@ public: ...@@ -87,7 +146,8 @@ public:
/* /*
A table. A table value. There is one Table_value object for every table that can
potentially be eliminated.
- table depends on any of its unique keys - table depends on any of its unique keys
- has its fields and embedding outer join as dependency. - has its fields and embedding outer join as dependency.
*/ */
...@@ -221,6 +281,7 @@ public: ...@@ -221,6 +281,7 @@ public:
MY_BITMAP expr_deps; MY_BITMAP expr_deps;
}; };
static static
bool build_eq_deps_for_cond(Table_elimination *te, Equality_module **fdeps, bool build_eq_deps_for_cond(Table_elimination *te, Equality_module **fdeps,
uint *and_level, Item *cond, uint *and_level, Item *cond,
...@@ -244,6 +305,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl); ...@@ -244,6 +305,7 @@ static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl);
#ifndef DBUG_OFF #ifndef DBUG_OFF
static void dbug_print_deps(Table_elimination *te); static void dbug_print_deps(Table_elimination *te);
#endif #endif
/*******************************************************************************************/ /*******************************************************************************************/
/* /*
...@@ -538,8 +600,8 @@ Equality_module *merge_func_deps(Equality_module *start, Equality_module *new_fi ...@@ -538,8 +600,8 @@ Equality_module *merge_func_deps(Equality_module *start, Equality_module *new_fi
static static
bool add_eq_dep(Table_elimination *te, Equality_module **eq_dep, bool add_eq_dep(Table_elimination *te, Equality_module **eq_dep,
uint and_level, Item_func *cond, uint and_level, Item_func *cond, Item *left, Item *right,
Item *left, Item *right, table_map usable_tables) table_map usable_tables)
{ {
if ((left->used_tables() & usable_tables) && if ((left->used_tables() & usable_tables) &&
!(right->used_tables() & RAND_TABLE_BIT) && !(right->used_tables() & RAND_TABLE_BIT) &&
...@@ -565,7 +627,6 @@ bool add_eq_dep(Table_elimination *te, Equality_module **eq_dep, ...@@ -565,7 +627,6 @@ bool add_eq_dep(Table_elimination *te, Equality_module **eq_dep,
} }
} }
/* Store possible eq field */
(*eq_dep)->type= Module_dep::MODULE_EXPRESSION; //psergey-todo; (*eq_dep)->type= Module_dep::MODULE_EXPRESSION; //psergey-todo;
if (!((*eq_dep)->field= get_field_value(te, field))) if (!((*eq_dep)->field= get_field_value(te, field)))
return TRUE; return TRUE;
...@@ -651,7 +712,8 @@ Outer_join_module *get_outer_join_dep(Table_elimination *te, ...@@ -651,7 +712,8 @@ Outer_join_module *get_outer_join_dep(Table_elimination *te,
table_map deps_map) table_map deps_map)
{ {
Outer_join_module *oj_dep; Outer_join_module *oj_dep;
oj_dep= new Outer_join_module(outer_join, my_count_bits(deps_map)); if (!(oj_dep= new Outer_join_module(outer_join, my_count_bits(deps_map))))
return NULL;
te->n_outer_joins++; te->n_outer_joins++;
/* /*
......
...@@ -8967,20 +8967,6 @@ static void restore_prev_nj_state(JOIN_TAB *last) ...@@ -8967,20 +8967,6 @@ static void restore_prev_nj_state(JOIN_TAB *last)
JOIN *join= last->join; JOIN *join= last->join;
while (last_emb) while (last_emb)
{ {
/*
psergey-elim: (nevermind)
new_prefix= cur_prefix & ~last;
if (!(new_prefix & cur_table_map)) // removed last inner table
{
join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
}
else (current)
{
// Won't hurt doing it all the time:
join->cur_embedding_map |= ...;
}
else
*/
if (!(--last_emb->nested_join->counter)) if (!(--last_emb->nested_join->counter))
join->cur_embedding_map&= ~last_emb->nested_join->nj_map; join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
else if (last_emb->nested_join->n_tables-1 == else if (last_emb->nested_join->n_tables-1 ==
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment