Commit 3ffa60fe authored by Sergey Petrunia's avatar Sergey Petrunia

MWL#17: Table elimination

- Moved table elimination code to sql/opt_table_elimination.cc
- Added comments 

.bzrignore:
  MWL#17: Table elimination
  - Moved table elimination code to sql/opt_table_elimination.cc
libmysqld/Makefile.am:
  MWL#17: Table elimination
  - Moved table elimination code to sql/opt_table_elimination.cc
sql/CMakeLists.txt:
  MWL#17: Table elimination
  - Moved table elimination code to sql/opt_table_elimination.cc
sql/Makefile.am:
  MWL#17: Table elimination
  - Moved table elimination code to sql/opt_table_elimination.cc
parent faf9a6d3
...@@ -1905,3 +1905,4 @@ sql/share/swedish ...@@ -1905,3 +1905,4 @@ sql/share/swedish
sql/share/ukrainian sql/share/ukrainian
libmysqld/examples/mysqltest.cc libmysqld/examples/mysqltest.cc
extra/libevent/event-config.h extra/libevent/event-config.h
libmysqld/opt_table_elimination.cc
...@@ -76,7 +76,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ ...@@ -76,7 +76,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \ rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \ sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc \ rpl_injector.cc my_user.c partition_info.cc \
sql_servers.cc event_parse_data.cc sql_servers.cc event_parse_data.cc opt_table_elimination.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources) libmysqld_int_a_SOURCES= $(libmysqld_sources)
nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources) nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
......
...@@ -73,7 +73,7 @@ ADD_EXECUTABLE(mysqld ...@@ -73,7 +73,7 @@ ADD_EXECUTABLE(mysqld
partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc rpl_rli.cc rpl_mi.cc sql_servers.cc
sql_connect.cc scheduler.cc sql_connect.cc scheduler.cc
sql_profile.cc event_parse_data.cc sql_profile.cc event_parse_data.cc opt_table_elimination.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
${PROJECT_SOURCE_DIR}/include/mysqld_error.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h
......
...@@ -121,7 +121,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ ...@@ -121,7 +121,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
event_queue.cc event_db_repository.cc events.cc \ event_queue.cc event_db_repository.cc events.cc \
sql_plugin.cc sql_binlog.cc \ sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc \ sql_builtin.cc sql_tablespace.cc partition_info.cc \
sql_servers.cc event_parse_data.cc sql_servers.cc event_parse_data.cc \
opt_table_elimination.cc
nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c
......
...@@ -1915,17 +1915,22 @@ void Item_field::reset_field(Field *f) ...@@ -1915,17 +1915,22 @@ void Item_field::reset_field(Field *f)
name= (char*) f->field_name; name= (char*) f->field_name;
} }
bool Item_field::check_column_usage_processor(uchar *arg) bool Item_field::check_column_usage_processor(uchar *arg)
{ {
Field_processor_info* info=(Field_processor_info*)arg; Field_processor_info* info=(Field_processor_info*)arg;
/* It is ok if this is a column of an allowed table: */
if (used_tables() & ~info->allowed_tables) if (used_tables() & ~info->allowed_tables)
return FALSE; return FALSE;
if (field->table == info->table) if (field->table == info->table)
{ {
/* It is not ok to use columns that are not part of the key of interest: */
if (!(field->part_of_key.is_set(info->keyno))) if (!(field->part_of_key.is_set(info->keyno)))
return TRUE; return TRUE;
/* Find which key part we're using and mark it in needed_key_parts */
KEY *key= &field->table->key_info[info->keyno]; KEY *key= &field->table->key_info[info->keyno];
for (uint part= 0; part < key->key_parts; part++) for (uint part= 0; part < key->key_parts; part++)
{ {
...@@ -1935,10 +1940,17 @@ bool Item_field::check_column_usage_processor(uchar *arg) ...@@ -1935,10 +1940,17 @@ bool Item_field::check_column_usage_processor(uchar *arg)
break; break;
} }
} }
return FALSE;
} }
return FALSE;
/*
We get here when this refers to a table that's neither the table of
interest, nor one of the allowed tables.
*/
return TRUE;
} }
const char *Item_ident::full_name() const const char *Item_ident::full_name() const
{ {
char *tmp; char *tmp;
......
...@@ -731,7 +731,11 @@ class Item { ...@@ -731,7 +731,11 @@ class Item {
virtual bool val_bool_result() { return val_bool(); } virtual bool val_bool_result() { return val_bool(); }
virtual bool is_null_result() { return is_null(); } virtual bool is_null_result() { return is_null(); }
/* bit map of tables used by item */ /*
Bitmap of tables used by item
(note: if you need to check dependencies on individual columns, check out
check_column_usage_processor)
*/
virtual table_map used_tables() const { return (table_map) 0L; } virtual table_map used_tables() const { return (table_map) 0L; }
/* /*
Return table map of tables that can't be NULL tables (tables that are Return table map of tables that can't be NULL tables (tables that are
...@@ -1013,7 +1017,7 @@ class Item { ...@@ -1013,7 +1017,7 @@ class Item {
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
}; };
/* Data for Item::check_column_usage_processor */
typedef struct typedef struct
{ {
table_map allowed_tables; table_map allowed_tables;
...@@ -1022,6 +1026,7 @@ typedef struct ...@@ -1022,6 +1026,7 @@ typedef struct
uint needed_key_parts; uint needed_key_parts;
} Field_processor_info; } Field_processor_info;
class sp_head; class sp_head;
......
...@@ -250,7 +250,7 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, ...@@ -250,7 +250,7 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
if (lex->having && (lex->having)->walk(processor, walk_subquery, if (lex->having && (lex->having)->walk(processor, walk_subquery,
argument)) argument))
return 1; return 1;
/* TODO: why doesn't this walk the OUTER JOINs' ON expressions */ /* TODO: why does this walk WHERE/HAVING but not ON expressions of outer joins? */
while ((item=li++)) while ((item=li++))
{ {
......
...@@ -351,9 +351,10 @@ class Item_sum :public Item_result_field ...@@ -351,9 +351,10 @@ class Item_sum :public Item_result_field
Return bitmap of tables that are needed to evaluate the item. Return bitmap of tables that are needed to evaluate the item.
The implementation takes into account the used strategy: items resolved The implementation takes into account the used strategy: items resolved
at optimization phase report 0. at optimization phase will report 0.
Items that depend on the number of rows only, e.g. COUNT(*) will report Items that depend on the number of join output records, but not columns
zero, but will still false from const_item(). of any particular table (like COUNT(*)) will report 0 from used_tables(),
but will still return false from const_item().
*/ */
table_map used_tables() const { return used_tables_cache; } table_map used_tables() const { return used_tables_cache; }
void update_used_tables (); void update_used_tables ();
......
This diff is collapsed.
This diff is collapsed.
...@@ -28,6 +28,11 @@ ...@@ -28,6 +28,11 @@
#include "procedure.h" #include "procedure.h"
#include <myisam.h> #include <myisam.h>
#define FT_KEYPART (MAX_REF_PARTS+10)
/* Values in optimize */
#define KEY_OPTIMIZE_EXISTS 1
#define KEY_OPTIMIZE_REF_OR_NULL 2
typedef struct keyuse_t { typedef struct keyuse_t {
TABLE *table; TABLE *table;
Item *val; /**< or value if no field */ Item *val; /**< or value if no field */
...@@ -51,6 +56,14 @@ typedef struct keyuse_t { ...@@ -51,6 +56,14 @@ typedef struct keyuse_t {
NULL - Otherwise (the source equality can't be turned off) NULL - Otherwise (the source equality can't be turned off)
*/ */
bool *cond_guard; bool *cond_guard;
/*
TRUE <=> This keyuse can be used to construct key access.
FALSE <=> Otherwise. Currently unusable KEYUSEs represent equalities
where one table column refers to another one, like this:
t.keyXpartA=func(t.keyXpartB)
This equality cannot be used for index access but is useful
for table elimination.
*/
bool usable; bool usable;
} KEYUSE; } KEYUSE;
...@@ -734,9 +747,13 @@ bool error_if_full_join(JOIN *join); ...@@ -734,9 +747,13 @@ bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error); int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab); int safe_index_read(JOIN_TAB *tab);
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value); COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key);
inline bool optimizer_flag(THD *thd, uint flag) inline bool optimizer_flag(THD *thd, uint flag)
{ {
return (thd->variables.optimizer_switch & flag); return (thd->variables.optimizer_switch & flag);
} }
void eliminate_tables(JOIN *join, uint *const_tbl_count,
table_map *const_tables);
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