Commit 5991efc3 authored by Alexander Barkov's avatar Alexander Barkov

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

Step #8: Adding get_mm_tree() in Item_func, Item_func_between,
Item_func_in, Item_equal. This removes one virtual call item->type()
in queries like:
  SELECT * FROM t1 WHERE c BETWEEN const1 AND const2;
  SELECT * FROM t1 WHERE c>const;
  SELECT * FROM t1 WHERE c IN (const_list);
parent a25ccd4f
...@@ -655,6 +655,7 @@ public: ...@@ -655,6 +655,7 @@ public:
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
uint *and_level, table_map usable_tables, uint *and_level, table_map usable_tables,
SARGABLE_PARAM **sargables); SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
}; };
...@@ -1337,6 +1338,7 @@ public: ...@@ -1337,6 +1338,7 @@ public:
{ return OPTIMIZE_KEY; } { return OPTIMIZE_KEY; }
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
table_map usable_tables, SARGABLE_PARAM **sargables); table_map usable_tables, SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
enum Functype functype() const { return IN_FUNC; } enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; } const char *func_name() const { return " IN "; }
...@@ -1927,6 +1929,7 @@ public: ...@@ -1927,6 +1929,7 @@ public:
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
uint *and_level, table_map usable_tables, uint *and_level, table_map usable_tables,
SARGABLE_PARAM **sargables); SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
bool walk(Item_processor processor, bool walk_subquery, uchar *arg); bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg); Item *transform(Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
......
...@@ -134,6 +134,7 @@ public: ...@@ -134,6 +134,7 @@ public:
COND *build_equal_items(THD *thd, COND_EQUAL *inherited, COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields, bool link_item_fields,
COND_EQUAL **cond_equal_ref); COND_EQUAL **cond_equal_ref);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
virtual bool have_rev_func() const { return 0; } virtual bool have_rev_func() const { return 0; }
......
...@@ -8053,19 +8053,10 @@ SEL_TREE *Item_cond::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) ...@@ -8053,19 +8053,10 @@ SEL_TREE *Item_cond::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
} }
SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) static SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param, Item *cond)
{ {
SEL_TREE *tree=0; DBUG_ENTER("get_mm_tree_for_const");
SEL_TREE *ftree= 0; if (cond->is_expensive())
Item_field *field_item= 0;
bool inv= FALSE;
Item *value= 0;
DBUG_ENTER("Item::get_mm_tree");
/* Here when simple cond */
if (const_item())
{
if (is_expensive())
DBUG_RETURN(0); DBUG_RETURN(0);
/* /*
During the cond->val_int() evaluation we can come across a subselect During the cond->val_int() evaluation we can come across a subselect
...@@ -8075,53 +8066,69 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) ...@@ -8075,53 +8066,69 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
*/ */
MEM_ROOT *tmp_root= param->mem_root; MEM_ROOT *tmp_root= param->mem_root;
param->thd->mem_root= param->old_root; param->thd->mem_root= param->old_root;
tree= val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) : SEL_TREE *tree;
tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE); new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
param->thd->mem_root= tmp_root; param->thd->mem_root= tmp_root;
DBUG_RETURN(tree); DBUG_RETURN(tree);
} }
table_map ref_tables= 0;
table_map param_comp= ~(param->prev_tables | param->read_tables | SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
param->current_table); {
if (type() != Item::FUNC_ITEM) DBUG_ENTER("Item::get_mm_tree");
{ // Should be a field if (const_item())
ref_tables= used_tables(); DBUG_RETURN(get_mm_tree_for_const(param, this));
/*
Here we have a not-constant non-function Item.
Item_field should not appear, as normalize_cond() replaces
"WHERE field" to "WHERE field<>0".
Item_exists_subselect is possible, e.g. in this query:
SELECT id, st FROM t1
WHERE st IN ('GA','FL') AND EXISTS (SELECT 1 FROM t2 WHERE t2.id=t1.id)
GROUP BY id;
*/
table_map ref_tables= used_tables();
if ((ref_tables & param->current_table) || if ((ref_tables & param->current_table) ||
(ref_tables & ~(param->prev_tables | param->read_tables))) (ref_tables & ~(param->prev_tables | param->read_tables)))
DBUG_RETURN(0); DBUG_RETURN(0);
DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
} }
Item_func *cond_func= (Item_func*) this;
if (cond_func->functype() == Item_func::BETWEEN || SEL_TREE *
cond_func->functype() == Item_func::IN_FUNC) Item_func_between::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
inv= ((Item_func_opt_neg *) cond_func)->negated; {
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_ENTER("Item::get_mm_tree");
DBUG_RETURN(0); if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
param->cond= this; param->cond= this;
switch (cond_func->functype()) { SEL_TREE *tree= 0;
case Item_func::BETWEEN: SEL_TREE *ftree= 0;
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{ {
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); ftree= get_full_func_mm_tree(param, this, field_item, NULL, negated);
} }
/* /*
Concerning the code below see the NOTES section in Concerning the code below see the NOTES section in
the comments for the function get_full_func_mm_tree() the comments for the function get_full_func_mm_tree()
*/ */
for (uint i= 1 ; i < cond_func->arg_count ; i++) for (uint i= 1 ; i < arg_count ; i++)
{ {
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM) if (arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
{ {
field_item= (Item_field*) (cond_func->arguments()[i]->real_item()); Item_field *field_item= (Item_field*) (arguments()[i]->real_item());
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, SEL_TREE *tmp= get_full_func_mm_tree(param, this, field_item,
field_item, (Item*)(intptr)i, inv); (Item*)(intptr) i, negated);
if (inv) if (negated)
{ {
tree= !tree ? tmp : tree_or(param, tree, tmp); tree= !tree ? tmp : tree_or(param, tree, tmp);
if (tree == NULL) if (tree == NULL)
...@@ -8130,31 +8137,53 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) ...@@ -8130,31 +8137,53 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
else else
tree= tree_and(param, tree, tmp); tree= tree_and(param, tree, tmp);
} }
else if (inv) else if (negated)
{ {
tree= 0; tree= 0;
break; break;
} }
} }
ftree = tree_and(param, ftree, tree); ftree= tree_and(param, ftree, tree);
break; DBUG_RETURN(ftree);
case Item_func::IN_FUNC: }
{
Item_func_in *func=(Item_func_in*) cond_func;
if (func->key_item()->real_item()->type() != Item::FIELD_ITEM) SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item_func_in::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
param->cond= this;
if (key_item()->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(0); DBUG_RETURN(0);
field_item= (Item_field*) (func->key_item()->real_item()); Item_field *field= (Item_field*) (key_item()->real_item());
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv); SEL_TREE *tree= get_full_func_mm_tree(param, this, field, NULL, negated);
break; DBUG_RETURN(tree);
} }
case Item_func::MULT_EQUAL_FUNC:
{
Item_equal *item_equal= (Item_equal *) this; SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
if (!(value= item_equal->get_const()) || value->is_expensive()) {
DBUG_ENTER("Item_equal::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
param->cond= this;
SEL_TREE *tree= 0;
SEL_TREE *ftree= 0;
Item *value;
if (!(value= get_const()) || value->is_expensive())
DBUG_RETURN(0); DBUG_RETURN(0);
Item_equal_fields_iterator it(*item_equal);
ref_tables= value->used_tables(); Item_equal_fields_iterator it(*this);
table_map ref_tables= value->used_tables();
table_map param_comp= ~(param->prev_tables | param->read_tables |
param->current_table);
while (it++) while (it++)
{ {
Field *field= it.get_curr_field(); Field *field= it.get_curr_field();
...@@ -8162,24 +8191,35 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) ...@@ -8162,24 +8191,35 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
if (!((ref_tables | field->table->map) & param_comp)) if (!((ref_tables | field->table->map) & param_comp))
{ {
tree= get_mm_parts(param, this, field, Item_func::EQ_FUNC, tree= get_mm_parts(param, this, field, Item_func::EQ_FUNC,
value,cmp_type); value, cmp_type);
ftree= !ftree ? tree : tree_and(param, ftree, tree); ftree= !ftree ? tree : tree_and(param, ftree, tree);
} }
} }
DBUG_RETURN(ftree); DBUG_RETURN(ftree);
} }
default:
DBUG_ASSERT (!ftree); SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) {
DBUG_ENTER("Item::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
if (select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0);
param->cond= this;
SEL_TREE *ftree= 0;
if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{ {
field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : NULL; Item *value= arg_count > 1 ? arguments()[1] : NULL;
if (value && value->is_expensive()) if (value && value->is_expensive())
DBUG_RETURN(0); DBUG_RETURN(0);
if (!cond_func->arguments()[0]->real_item()->const_item()) if (!arguments()[0]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); ftree= get_full_func_mm_tree(param, this, field_item, value, false);
} }
/* /*
Even if get_full_func_mm_tree() was executed above and did not Even if get_full_func_mm_tree() was executed above and did not
...@@ -8197,16 +8237,15 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) ...@@ -8197,16 +8237,15 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
call to get_full_func_mm_tree() with reversed operands (see call to get_full_func_mm_tree() with reversed operands (see
below) may succeed. below) may succeed.
*/ */
if (!ftree && cond_func->have_rev_func() && if (!ftree && have_rev_func() &&
cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM) arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
{ {
field_item= (Item_field*) (cond_func->arguments()[1]->real_item()); Item_field *field_item= (Item_field*) (arguments()[1]->real_item());
value= cond_func->arguments()[0]; Item *value= arguments()[0];
if (value && value->is_expensive()) if (value && value->is_expensive())
DBUG_RETURN(0); DBUG_RETURN(0);
if (!cond_func->arguments()[1]->real_item()->const_item()) if (!arguments()[1]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv); ftree= get_full_func_mm_tree(param, this, field_item, value, false);
}
} }
DBUG_RETURN(ftree); DBUG_RETURN(ftree);
......
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