1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-09 22:24:09 +03:00

MDEV-7950 Item_func::type() takes 0.26% in OLTP RO

Step#2:

1. Removes the function build_equal_items_for_cond() and
   introduces a new method Item::build_equal_items() instead,
   with specific implementations in the following Items:

   Item  (the default implementation)
   Item_ident_or_func_or_sum
   Item_cond
   Item_cond_and

2. Adds a new abstract class Item_ident_or_func_or_sum,
   a common parent for Item_ident and Item_func_or_sum,
   as they have exactly the same build_equal_items().

3. Renames Item_cond_and::cond_equal to Item_cond_and::m_cond_equal,
   to avoid confusion between the member and local variables named
   "cond_equal".
This commit is contained in:
Alexander Barkov
2015-04-28 14:06:07 +04:00
parent 46816996c8
commit c8141f5314
4 changed files with 220 additions and 186 deletions

View File

@@ -734,7 +734,7 @@ Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg)
*/
Item_ident::Item_ident(THD *thd, Item_ident *item)
:Item_result_field(thd, item),
:Item_ident_or_func_or_sum(thd, item),
orig_db_name(item->orig_db_name),
orig_table_name(item->orig_table_name),
orig_field_name(item->orig_field_name),

View File

@@ -1127,6 +1127,12 @@ public:
void print_item_w_name(String *, enum_query_type query_type);
void print_value(String *);
virtual void update_used_tables() {}
virtual COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields)
{
update_used_tables();
return this;
}
virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields) {}
/* Called for items that really have to be split */
@@ -2128,7 +2134,19 @@ public:
};
class Item_ident :public Item_result_field
class Item_ident_or_func_or_sum: public Item_result_field
{
public:
Item_ident_or_func_or_sum(): Item_result_field() { }
Item_ident_or_func_or_sum(THD *thd, Item_ident_or_func_or_sum *item)
:Item_result_field(thd, item)
{ }
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields);
};
class Item_ident :public Item_ident_or_func_or_sum
{
protected:
/*
@@ -3441,25 +3459,20 @@ public:
An abstract class representing common features of
regular functions and aggregate functions.
*/
class Item_func_or_sum: public Item_result_field, public Item_args
class Item_func_or_sum: public Item_ident_or_func_or_sum, public Item_args
{
public:
Item_func_or_sum()
:Item_result_field(), Item_args() {}
Item_func_or_sum(Item *a)
:Item_result_field(), Item_args(a) { }
Item_func_or_sum(Item *a, Item *b)
:Item_result_field(), Item_args(a, b) { }
Item_func_or_sum(Item *a, Item *b, Item *c)
:Item_result_field(), Item_args(a, b, c) { }
Item_func_or_sum() :Item_args() {}
Item_func_or_sum(Item *a) :Item_args(a) { }
Item_func_or_sum(Item *a, Item *b) :Item_args(a, b) { }
Item_func_or_sum(Item *a, Item *b, Item *c) :Item_args(a, b, c) { }
Item_func_or_sum(Item *a, Item *b, Item *c, Item *d)
:Item_result_field(), Item_args(a, b, c, d) { }
:Item_args(a, b, c, d) { }
Item_func_or_sum(Item *a, Item *b, Item *c, Item *d, Item *e)
:Item_result_field(), Item_args(a, b, c, d, e) { }
:Item_args(a, b, c, d, e) { }
Item_func_or_sum(THD *thd, Item_func_or_sum *item)
:Item_result_field(thd, item), Item_args(thd, item) { }
Item_func_or_sum(List<Item> &list)
:Item_result_field(), Item_args(list) { }
:Item_ident_or_func_or_sum(thd, item), Item_args(thd, item) { }
Item_func_or_sum(List<Item> &list) :Item_args(list) { }
bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
if (walk_args(processor, walk_subquery, arg))

View File

@@ -1768,6 +1768,8 @@ public:
used_tables_and_const_cache_init();
used_tables_and_const_cache_update_and_join(list);
}
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields);
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,
@@ -2078,7 +2080,7 @@ public:
class Item_cond_and :public Item_cond
{
public:
COND_EQUAL cond_equal; /* contains list of Item_equal objects for
COND_EQUAL m_cond_equal; /* contains list of Item_equal objects for
the current and level and reference
to multiple equalities of upper and levels */
Item_cond_and() :Item_cond() {}
@@ -2101,6 +2103,8 @@ public:
void mark_as_condition_AND_part(TABLE_LIST *embedding);
virtual uint exists2in_reserved_items() { return list.elements; };
bool walk_top_and(Item_processor processor, uchar *arg);
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields);
};
inline bool is_cond_and(Item *item)

View File

@@ -3865,7 +3865,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
conds= remove_eq_conds(join->thd, conds, &join->cond_value);
if (conds && conds->type() == Item::COND_ITEM &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
join->cond_equal= &((Item_cond_and*) conds)->cond_equal;
join->cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
join->select_lex->where= conds;
if (join->cond_value == Item::COND_FALSE)
{
@@ -3878,7 +3878,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
{
if (conds->type() == Item::COND_ITEM &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
join->cond_equal= (&((Item_cond_and *) conds)->cond_equal);
join->cond_equal= (&((Item_cond_and *) conds)->m_cond_equal);
else if (conds->type() == Item::FUNC_ITEM &&
((Item_func*) conds)->functype() == Item_func::MULT_EQUAL_FUNC)
{
@@ -4050,7 +4050,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
((Item_cond*) (join->conds))->functype() ==
Item_func::COND_AND_FUNC &&
join->cond_equal ==
&((Item_cond_and *) (join->conds))->cond_equal) ||
&((Item_cond_and *) (join->conds))->m_cond_equal) ||
(join->conds->type() == Item::FUNC_ITEM &&
((Item_func*) (join->conds))->functype() ==
Item_func::MULT_EQUAL_FUNC &&
@@ -12377,7 +12377,7 @@ finish:
general case, its own constant for each fields from the multiple
equality. But at the same time it would allow us to get rid
of constant propagation completely: it would be done by the call
to build_equal_items_for_cond.
to cond->build_equal_items().
The implementation does not follow exactly the above rules to
@@ -12710,7 +12710,10 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
/**
Replace all equality predicates in a condition by multiple equality items.
Item_xxx::build_equal_items()
Replace all equality predicates in a condition referenced by "this"
by multiple equality items.
At each 'and' level the function detects items for equality predicates
and replaced them by a set of multiple equality items of class Item_equal,
@@ -12766,7 +12769,6 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
all possible Item_equal objects in upper levels.
@param thd thread handle
@param cond condition(expression) where to make replacement
@param inherited path to all inherited multiple equality items
@return
@@ -12775,7 +12777,7 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
so no additional update_used_tables() is needed on the result.
*/
static COND *build_equal_items_for_cond(THD *thd, COND *cond,
COND *Item_cond_and::build_equal_items(THD *thd,
COND_EQUAL *inherited,
bool link_item_fields)
{
@@ -12783,18 +12785,12 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
COND_EQUAL cond_equal;
cond_equal.upper_levels= inherited;
if (cond->type() == Item::COND_ITEM)
{
List<Item> eq_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<Item> *args= argument_list();
List_iterator<Item> li(*args);
Item *item;
if (and_level)
{
/*
Retrieve all conjuncts of this level detecting the equality
that are subject to substitution by multiple equality items and
@@ -12831,22 +12827,19 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
item_equal->n_field_items());
}
((Item_cond_and*)cond)->cond_equal.copy(cond_equal);
cond_equal.current_level=
((Item_cond_and*)cond)->cond_equal.current_level;
inherited= &(((Item_cond_and*)cond)->cond_equal);
}
m_cond_equal.copy(cond_equal);
cond_equal.current_level= m_cond_equal.current_level;
inherited= &m_cond_equal;
/*
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;
if ((new_item= build_equal_items_for_cond(thd, item, inherited, FALSE))
if ((new_item= item->build_equal_items(thd, inherited, FALSE))
!= item)
{
/* This replacement happens only for standalone equalities */
@@ -12857,31 +12850,55 @@ 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);
update_used_tables();
return this;
}
COND *Item_cond::build_equal_items(THD *thd,
COND_EQUAL *inherited,
bool link_item_fields)
{
List<Item> *args= argument_list();
List_iterator<Item> li(*args);
Item *item;
/*
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.
Make replacement of equality predicates for lower levels
of the condition expression.
Update used_tables_cache and const_item_cache on the way.
*/
cond_item->update_used_tables();
}
return cond_item;
}
else if (cond->type() == Item::FUNC_ITEM ||
cond->real_item()->type() == Item::FIELD_ITEM)
used_tables_and_const_cache_init();
while ((item= li++))
{
Item *new_item;
if ((new_item= item->build_equal_items(thd, inherited, FALSE))
!= item)
{
/* This replacement happens only for standalone equalities */
/*
This is ok with PS/SP as the replacement is done for
arguments of an AND/OR item, which are restored for each
execution of PS/SP.
*/
li.replace(new_item);
}
used_tables_and_const_cache_join(new_item);
}
return this;
}
COND *Item_ident_or_func_or_sum::build_equal_items(THD *thd,
COND_EQUAL *inherited,
bool link_item_fields)
{
COND_EQUAL cond_equal;
cond_equal.upper_levels= inherited;
List<Item> eq_list;
/*
If an equality predicate forms the whole and level,
@@ -12893,8 +12910,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
for WHERE a=b AND c=d AND (b=c OR d=5)
b=c is replaced by =(a,b,c,d).
*/
if (check_equality(thd, cond, &cond_equal, &eq_list))
if (check_equality(thd, this, &cond_equal, &eq_list))
{
Item_equal *item_equal;
int n= cond_equal.current_level.elements + eq_list.elements;
if (n == 0)
return new Item_int((longlong) 1,1);
@@ -12930,8 +12948,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->n_field_items());
}
and_cond->cond_equal.copy(cond_equal);
cond_equal.current_level= and_cond->cond_equal.current_level;
and_cond->m_cond_equal.copy(cond_equal);
cond_equal.current_level= and_cond->m_cond_equal.current_level;
args->append((List<Item> *)&cond_equal.current_level);
and_cond->update_used_tables();
return and_cond;
@@ -12944,11 +12962,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
an argument of a comparison predicate.
*/
uchar* is_subst_valid= (uchar *) Item::ANY_SUBST;
cond= cond->compile(&Item::subst_argument_checker,
COND *cond= compile(&Item::subst_argument_checker,
&is_subst_valid,
&Item::equal_fields_propagator,
(uchar *) inherited);
}
cond->update_used_tables();
return cond;
}
@@ -12958,7 +12975,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
Build multiple equalities for a condition and all on expressions that
inherit these multiple equalities.
The function first applies the build_equal_items_for_cond function
The function first applies the cond->build_equal_items() method
to build all multiple equalities for condition cond utilizing equalities
referred through the parameter inherited. The extended set of
equalities is returned in the structure referred by the cond_equal_ref
@@ -13035,10 +13052,10 @@ static COND *build_equal_items(JOIN *join, COND *cond,
if (cond)
{
cond= build_equal_items_for_cond(thd, cond, inherited, link_equal_fields);
cond= cond->build_equal_items(thd, inherited, link_equal_fields);
if (cond->type() == Item::COND_ITEM &&
((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
cond_equal= &((Item_cond_and*) cond)->cond_equal;
cond_equal= &((Item_cond_and*) cond)->m_cond_equal;
else if (cond->type() == Item::FUNC_ITEM &&
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
@@ -13516,7 +13533,7 @@ static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab,
Item_func::COND_AND_FUNC;
if (and_level)
{
cond_equal= &((Item_cond_and *) cond)->cond_equal;
cond_equal= &((Item_cond_and *) cond)->m_cond_equal;
cond_list->disjoin((List<Item> *) &cond_equal->current_level);/* remove Item_equal objects from the AND. */
List_iterator_fast<Item_equal> it(cond_equal->current_level);
@@ -14667,7 +14684,7 @@ optimize_cond(JOIN *join, COND *conds,
conds= remove_eq_conds(thd, conds, cond_value);
if (conds && conds->type() == Item::COND_ITEM &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
*cond_equal= &((Item_cond_and*) conds)->cond_equal;
*cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY););
}
DBUG_RETURN(conds);
@@ -14708,8 +14725,8 @@ void propagate_new_equalities(THD *thd, Item *cond,
if (and_level)
{
Item_cond_and *cond_and= (Item_cond_and *) cond;
List<Item_equal> *cond_equalities= &cond_and->cond_equal.current_level;
cond_and->cond_equal.upper_levels= inherited;
List<Item_equal> *cond_equalities= &cond_and->m_cond_equal.current_level;
cond_and->m_cond_equal.upper_levels= inherited;
if (!cond_equalities->is_empty() && cond_equalities != new_equalities)
{
Item_equal *equal_item;
@@ -14735,7 +14752,7 @@ void propagate_new_equalities(THD *thd, Item *cond,
while ((item= li++))
{
COND_EQUAL *new_inherited= and_level && item->type() == Item::COND_ITEM ?
&((Item_cond_and *) cond)->cond_equal :
&((Item_cond_and *) cond)->m_cond_equal :
inherited;
propagate_new_equalities(thd, item, new_equalities, new_inherited,
is_simplifiable_cond);
@@ -14920,7 +14937,7 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
So it's easier to do it at one pass through the list of the equalities.
*/
List<Item_equal> *cond_equalities=
&((Item_cond_and *) cond)->cond_equal.current_level;
&((Item_cond_and *) cond)->m_cond_equal.current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
List_iterator<Item_equal> it(*cond_equalities);
Item_equal *eq_item;
@@ -14976,7 +14993,7 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
of cond_arg_list.
*/
List<Item_equal> *new_item_equalities=
&((Item_cond_and *) new_item)->cond_equal.current_level;
&((Item_cond_and *) new_item)->m_cond_equal.current_level;
if (!new_item_equalities->is_empty())
{
/*
@@ -15062,7 +15079,7 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
These multiple equalities are to be merged into the
multiple equalities of cond_arg_list.
*/
COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->cond_equal;
COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal;
List<Item_equal> *cond_equalities= &cond_equal->current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
Item_equal *equality;