diff options
author | Alexander Barkov <bar@mariadb.org> | 2015-04-22 12:40:23 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2015-04-22 12:40:23 +0400 |
commit | fc1f301e91367be5de7b5dc510acb1a6e22d59b5 (patch) | |
tree | de29ce0100b053cc9617ea04f2555ea6140912ff | |
parent | e7a7ea7ec107089c42315064fa238ec2cca92110 (diff) | |
download | mariadb-git-fc1f301e91367be5de7b5dc510acb1a6e22d59b5.tar.gz |
MDEV-8024 Remove excessive update_used_tables() calls
-rw-r--r-- | sql/item.cc | 16 | ||||
-rw-r--r-- | sql/item.h | 66 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 35 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 6 | ||||
-rw-r--r-- | sql/item_func.cc | 39 | ||||
-rw-r--r-- | sql/item_func.h | 29 | ||||
-rw-r--r-- | sql/item_row.cc | 25 | ||||
-rw-r--r-- | sql/item_row.h | 14 | ||||
-rw-r--r-- | sql/item_subselect.cc | 5 | ||||
-rw-r--r-- | sql/item_subselect.h | 7 | ||||
-rw-r--r-- | sql/sql_select.cc | 37 | ||||
-rw-r--r-- | sql/sql_udf.h | 4 |
12 files changed, 156 insertions, 127 deletions
diff --git a/sql/item.cc b/sql/item.cc index e9bbdc7f175..5433f1e8ff2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4730,10 +4730,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) else { Item::Type ref_type= (*reference)->type(); - prev_subselect_item->used_tables_cache|= - (*reference)->used_tables(); - prev_subselect_item->const_item_cache&= - (*reference)->const_item(); + prev_subselect_item->used_tables_and_const_cache_join(*reference); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? @@ -4759,8 +4756,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); - prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); - prev_subselect_item->const_item_cache&= (*ref)->const_item(); + prev_subselect_item->used_tables_and_const_cache_join(*ref); break; } } @@ -6783,8 +6779,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); - prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); - prev_subselect_item->const_item_cache&= (*ref)->const_item(); + prev_subselect_item->used_tables_and_const_cache_join(*ref); break; } /* @@ -6828,10 +6823,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (from_field == view_ref_found) { Item::Type refer_type= (*reference)->type(); - prev_subselect_item->used_tables_cache|= - (*reference)->used_tables(); - prev_subselect_item->const_item_cache&= - (*reference)->const_item(); + prev_subselect_item->used_tables_and_const_cache_join(*reference); DBUG_ASSERT((*reference)->type() == REF_ITEM); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, diff --git a/sql/item.h b/sql/item.h index 5820f119cab..4b42db2aa9e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3328,6 +3328,72 @@ public: }; +class Used_tables_and_const_cache +{ +public: + /* + In some cases used_tables_cache is not what used_tables() return + so the method should be used where one need used tables bit map + (even internally in Item_func_* code). + */ + table_map used_tables_cache; + bool const_item_cache; + + Used_tables_and_const_cache() + :used_tables_cache(0), + const_item_cache(true) + { } + Used_tables_and_const_cache(const Used_tables_and_const_cache *other) + :used_tables_cache(other->used_tables_cache), + const_item_cache(other->const_item_cache) + { } + void used_tables_and_const_cache_init() + { + used_tables_cache= 0; + const_item_cache= true; + } + void used_tables_and_const_cache_copy(const Used_tables_and_const_cache *c) + { + *this= *c; + } + void used_tables_and_const_cache_join(const Item *item) + { + used_tables_cache|= item->used_tables(); + const_item_cache&= item->const_item(); + } + /* + Call update_used_tables() for all "argc" items in the array "argv" + and join with the current cache. + "this" must be initialized with a constructor or + re-initialized with used_tables_and_const_cache_init(). + */ + void used_tables_and_const_cache_update_and_join(uint argc, Item **argv) + { + for (uint i=0 ; i < argc ; i++) + { + argv[i]->update_used_tables(); + used_tables_and_const_cache_join(argv[i]); + } + } + /* + Call update_used_tables() for all items in the list + and join with the current cache. + "this" must be initialized with a constructor or + re-initialized with used_tables_and_const_cache_init(). + */ + void used_tables_and_const_cache_update_and_join(List<Item> &list) + { + List_iterator_fast<Item> li(list); + Item *item; + while ((item=li++)) + { + item->update_used_tables(); + used_tables_and_const_cache_join(item); + } + } +}; + + /** An abstract class representing common features of regular functions and aggregate functions. diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 23676d722a3..eec99d906b2 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1520,9 +1520,8 @@ bool Item_in_optimizer::fix_left(THD *thd) if (args[1]->fixed) { /* to avoid overriding is called to update left expression */ - used_tables_cache|= args[1]->used_tables(); + used_tables_and_const_cache_join(args[1]); with_sum_func= with_sum_func || args[1]->with_sum_func; - const_item_cache= const_item_cache && args[1]->const_item(); } DBUG_RETURN(0); } @@ -1551,8 +1550,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) with_subselect= 1; with_sum_func= with_sum_func || args[1]->with_sum_func; with_field= with_field || args[1]->with_field; - used_tables_cache|= args[1]->used_tables(); - const_item_cache&= args[1]->const_item(); + used_tables_and_const_cache_join(args[1]); fixed= 1; return FALSE; } @@ -2081,11 +2079,10 @@ void Item_func_interval::fix_length_and_dec() } maybe_null= 0; max_length= 2; - used_tables_cache|= row->used_tables(); + used_tables_and_const_cache_join(row); not_null_tables_cache= row->not_null_tables(); with_sum_func= with_sum_func || row->with_sum_func; with_field= with_field || row->with_field; - const_item_cache&= row->const_item(); } @@ -4302,8 +4299,8 @@ Item_cond::fix_fields(THD *thd, Item **ref) List_iterator<Item> li(list); Item *item; uchar buff[sizeof(char*)]; // Max local vars in function - not_null_tables_cache= used_tables_cache= 0; - const_item_cache= 1; + not_null_tables_cache= 0; + used_tables_and_const_cache_init(); /* and_table_cache is the value that Item_cond_or() returns for @@ -4453,8 +4450,7 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref) List_iterator<Item> li(list); Item *item; - used_tables_cache=0; - const_item_cache=1; + used_tables_and_const_cache_init(); and_tables_cache= ~(table_map) 0; // Here and below we do as fix_fields does not_null_tables_cache= 0; @@ -4464,8 +4460,7 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref) table_map tmp_table_map; item->fix_after_pullout(new_parent, li.ref()); item= *li.ref(); - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); + used_tables_and_const_cache_join(item); if (item->const_item()) and_tables_cache= (table_map) 0; @@ -4648,22 +4643,6 @@ Item_cond::used_tables() const } -void Item_cond::update_used_tables() -{ - List_iterator_fast<Item> li(list); - Item *item; - - used_tables_cache=0; - const_item_cache=1; - while ((item=li++)) - { - item->update_used_tables(); - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); - } -} - - void Item_cond::print(String *str, enum_query_type query_type) { str->append('('); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 2d039d5e7b7..bf388ef9c01 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1763,7 +1763,11 @@ public: enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } table_map used_tables() const; - void update_used_tables(); + void update_used_tables() + { + used_tables_and_const_cache_init(); + used_tables_and_const_cache_update_and_join(list); + } virtual void print(String *str, enum_query_type query_type); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, diff --git a/sql/item_func.cc b/sql/item_func.cc index 50bc85f2c73..fb4b78df875 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -178,8 +178,14 @@ Item_func::fix_fields(THD *thd, Item **ref) Item **arg,**arg_end; uchar buff[STACK_BUFF_ALLOC]; // Max argument in function - used_tables_cache= not_null_tables_cache= 0; - const_item_cache=1; + /* + The Used_tables_and_const_cache of "this" was initialized by + the constructor, or by Item_func::cleanup(). + */ + DBUG_ASSERT(used_tables_cache == 0); + DBUG_ASSERT(const_item_cache == true); + + not_null_tables_cache= 0; /* Use stack limit of STACK_MIN_SIZE * 2 since @@ -221,8 +227,7 @@ Item_func::fix_fields(THD *thd, Item **ref) with_sum_func= with_sum_func || item->with_sum_func; with_field= with_field || item->with_field; - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); + used_tables_and_const_cache_join(item); with_subselect|= item->has_subquery(); } } @@ -269,8 +274,8 @@ void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref) { Item **arg,**arg_end; - used_tables_cache= not_null_tables_cache= 0; - const_item_cache=1; + used_tables_and_const_cache_init(); + not_null_tables_cache= 0; if (arg_count) { @@ -279,9 +284,8 @@ void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref) (*arg)->fix_after_pullout(new_parent, arg); Item *item= *arg; - used_tables_cache|= item->used_tables(); + used_tables_and_const_cache_join(item); not_null_tables_cache|= item->not_null_tables(); - const_item_cache&= item->const_item(); } } } @@ -436,19 +440,6 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, } -void Item_func::update_used_tables() -{ - used_tables_cache=0; - const_item_cache=1; - for (uint i=0 ; i < arg_count ; i++) - { - args[i]->update_used_tables(); - used_tables_cache|=args[i]->used_tables(); - const_item_cache&=args[i]->const_item(); - } -} - - table_map Item_func::used_tables() const { return used_tables_cache; @@ -3503,8 +3494,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func, /* Fix all arguments */ func->maybe_null=0; - used_tables_cache=0; - const_item_cache=1; + used_tables_and_const_cache_init(); if ((f_args.arg_count=arg_count)) { @@ -3546,8 +3536,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func, func->with_sum_func= func->with_sum_func || item->with_sum_func; func->with_field= func->with_field || item->with_field; func->with_subselect|= item->with_subselect; - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); + used_tables_and_const_cache_join(item); f_args.arg_type[i]=item->result_type(); } //TODO: why all following memory is not allocated with 1 call of sql_alloc? diff --git a/sql/item_func.h b/sql/item_func.h index 653c08e58c8..1b7988ab3cf 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -31,7 +31,7 @@ extern "C" /* Bug in BSDI include file */ #endif -class Item_func :public Item_func_or_sum +class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache { void sync_with_sum_func_and_with_field(List<Item> &list); protected: @@ -42,15 +42,8 @@ protected: uint allowed_arg_cols; String *val_str_from_val_str_ascii(String *str, String *str2); public: - /* - In some cases used_tables_cache is not what used_tables() return - so the method should be used where one need used tables bit map - (even internally in Item_func_* code). - */ - table_map used_tables_cache; table_map not_null_tables_cache; - bool const_item_cache; enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, @@ -118,19 +111,26 @@ public: } // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item) - :Item_func_or_sum(thd, item), + :Item_func_or_sum(thd, item), Used_tables_and_const_cache(item), allowed_arg_cols(item->allowed_arg_cols), - used_tables_cache(item->used_tables_cache), - not_null_tables_cache(item->not_null_tables_cache), - const_item_cache(item->const_item_cache) + not_null_tables_cache(item->not_null_tables_cache) { } bool fix_fields(THD *, Item **ref); + void cleanup() + { + Item_func_or_sum::cleanup(); + used_tables_and_const_cache_init(); + } void fix_after_pullout(st_select_lex *new_parent, Item **ref); void quick_fix_field(); table_map used_tables() const; table_map not_null_tables() const; - void update_used_tables(); + void update_used_tables() + { + used_tables_and_const_cache_init(); + used_tables_and_const_cache_update_and_join(arg_count, args); + } bool eq(const Item *item, bool binary_cmp) const; virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual bool have_rev_func() const { return 0; } @@ -1367,8 +1367,7 @@ public: { DBUG_ASSERT(fixed == 0); bool res= udf.fix_fields(thd, this, arg_count, args); - used_tables_cache= udf.used_tables_cache; - const_item_cache= udf.const_item_cache; + used_tables_and_const_cache_copy(&udf); fixed= 1; return res; } diff --git a/sql/item_row.cc b/sql/item_row.cc index 3548a6b9b75..1fc2000813b 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -39,8 +39,7 @@ */ Item_row::Item_row(List<Item> &arg): - Item(), used_tables_cache(0), not_null_tables_cache(0), - const_item_cache(1), with_null(0) + Item(), Used_tables_and_const_cache(), not_null_tables_cache(0), with_null(0) { //TODO: think placing 2-3 component items in item (as it done for function) @@ -126,8 +125,7 @@ void Item_row::cleanup() Item::cleanup(); /* Reset to the original values */ - used_tables_cache= 0; - const_item_cache= 1; + used_tables_and_const_cache_init(); with_null= 0; DBUG_VOID_RETURN; @@ -143,29 +141,14 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array, } -void Item_row::update_used_tables() -{ - used_tables_cache= 0; - const_item_cache= 1; - for (uint i= 0; i < arg_count; i++) - { - items[i]->update_used_tables(); - used_tables_cache|= items[i]->used_tables(); - const_item_cache&= items[i]->const_item(); - } -} - - void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref) { - used_tables_cache= 0; - const_item_cache= 1; + used_tables_and_const_cache_init(); not_null_tables_cache= 0; for (uint i= 0; i < arg_count; i++) { items[i]->fix_after_pullout(new_parent, &items[i]); - used_tables_cache|= items[i]->used_tables(); - const_item_cache&= items[i]->const_item(); + used_tables_and_const_cache_join(items[i]); not_null_tables_cache|= items[i]->not_null_tables(); } } diff --git a/sql/item_row.h b/sql/item_row.h index aa56068f8ba..31efc015909 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -17,22 +17,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -class Item_row: public Item +class Item_row: public Item, private Used_tables_and_const_cache { Item **items; - table_map used_tables_cache, not_null_tables_cache; + table_map not_null_tables_cache; uint arg_count; - bool const_item_cache; bool with_null; public: Item_row(List<Item> &); Item_row(Item_row *item): Item(), + Used_tables_and_const_cache(item), items(item->items), - used_tables_cache(item->used_tables_cache), not_null_tables_cache(0), arg_count(item->arg_count), - const_item_cache(item->const_item_cache), with_null(0) {} @@ -71,7 +69,11 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } Item_result cmp_type() const { return ROW_RESULT; } - void update_used_tables(); + void update_used_tables() + { + used_tables_and_const_cache_init(); + used_tables_and_const_cache_update_and_join(arg_count, items); + } table_map not_null_tables() const { return not_null_tables_cache; } virtual void print(String *str, enum_query_type query_type); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 32d63628cb5..496cb1185c8 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -49,8 +49,9 @@ const char *exists_outer_expr_name= "<exists outer expr>"; int check_and_do_in_subquery_rewrites(JOIN *join); Item_subselect::Item_subselect(): - Item_result_field(), value_assigned(0), own_engine(0), thd(0), old_engine(0), - used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1), + Item_result_field(), Used_tables_and_const_cache(), + value_assigned(0), own_engine(0), thd(0), old_engine(0), + have_to_be_excluded(0), inside_first_fix_fields(0), done_first_fix_fields(FALSE), expr_cache(0), forced_const(FALSE), substitution(0), engine(0), eliminated(FALSE), changed(0), is_correlated(FALSE) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index add2e0b6f9b..47a143e172a 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -44,7 +44,8 @@ class Cached_item; /* base class for subselects */ -class Item_subselect :public Item_result_field +class Item_subselect :public Item_result_field, + protected Used_tables_and_const_cache { bool value_assigned; /* value already assigned to subselect */ bool own_engine; /* the engine was not taken from other Item_subselect */ @@ -53,16 +54,12 @@ protected: THD *thd; /* old engine if engine was changed */ subselect_engine *old_engine; - /* cache of used external tables */ - table_map used_tables_cache; /* allowed number of columns (1 for single value subqueries) */ uint max_columns; /* where subquery is placed */ enum_parsing_place parsing_place; /* work with 'substitution' */ bool have_to_be_excluded; - /* cache of constant state */ - bool const_item_cache; bool inside_first_fix_fields; bool done_first_fix_fields; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 20a829eae23..476adb78925 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12770,7 +12770,9 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, @param inherited path to all inherited multiple equality items @return - pointer to the transformed condition + pointer to the transformed condition, + whose Used_tables_and_const_cache is up to date, + so no additional update_used_tables() is needed on the result. */ static COND *build_equal_items_for_cond(THD *thd, COND *cond, @@ -12784,9 +12786,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, if (cond->type() == Item::COND_ITEM) { List<Item> eq_list; - bool and_level= ((Item_cond*) cond)->functype() == - Item_func::COND_AND_FUNC; - List<Item> *args= ((Item_cond*) cond)->argument_list(); + Item_cond *cond_item= (Item_cond*) cond; + bool and_level= cond_item->functype() == Item_func::COND_AND_FUNC; + List<Item> *args= cond_item->argument_list(); List_iterator<Item> li(*args); Item *item; @@ -12837,8 +12839,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, /* Make replacement of equality predicates for lower levels of the condition expression. + Update used_tables_cache and const_item_cache on the way. */ li.rewind(); + cond_item->used_tables_and_const_cache_init(); while ((item= li++)) { Item *new_item; @@ -12853,12 +12857,27 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, */ li.replace(new_item); } + cond_item->used_tables_and_const_cache_join(new_item); } if (and_level) { args->append(&eq_list); args->append((List<Item> *)&cond_equal.current_level); + /* + Instead of the cond_item->update_used_tables() call below, + we could do this: + + cond_item->used_tables_and_const_cache_update_and_join(eq_list); + cond_item->used_tables_and_const_cache_update_and_join( + *(List<Item> *) &cond_equal.current_level); + + But initializing 2 iterators will probably be even slower than + redundant iterations over the topmost elements in "args", + which were already processed in the "while" loop above. + */ + cond_item->update_used_tables(); } + return cond_item; } else if (cond->type() == Item::FUNC_ITEM || cond->real_item()->type() == Item::FIELD_ITEM) @@ -12890,8 +12909,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, item_equal->upper_levels= inherited; return item_equal; } - - return eq_list.pop(); + Item *res= eq_list.pop(); + res->update_used_tables(); + return res; } else { @@ -12913,7 +12933,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, and_cond->cond_equal.copy(cond_equal); cond_equal.current_level= and_cond->cond_equal.current_level; args->append((List<Item> *)&cond_equal.current_level); - + and_cond->update_used_tables(); return and_cond; } } @@ -12928,8 +12948,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, &is_subst_valid, &Item::equal_fields_propagator, (uchar *) inherited); - cond->update_used_tables(); } + cond->update_used_tables(); return cond; } @@ -13016,7 +13036,6 @@ static COND *build_equal_items(JOIN *join, COND *cond, if (cond) { cond= build_equal_items_for_cond(thd, cond, inherited, link_equal_fields); - cond->update_used_tables(); if (cond->type() == Item::COND_ITEM && ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) cond_equal= &((Item_cond_and*) cond)->cond_equal; diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 076c5440aef..700f868eea4 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -52,7 +52,7 @@ typedef struct st_udf_func class Item_result_field; -class udf_handler :public Sql_alloc +class udf_handler :public Sql_alloc, public Used_tables_and_const_cache { protected: udf_func *u_d; @@ -65,8 +65,6 @@ class udf_handler :public Sql_alloc Item **args; public: - table_map used_tables_cache; - bool const_item_cache; bool not_original; udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), is_null(0), initialized(0), not_original(0) |