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:
void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
uint *and_level, table_map usable_tables,
SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
};
......@@ -1337,6 +1338,7 @@ public:
{ return OPTIMIZE_KEY; }
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
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);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
......@@ -1927,6 +1929,7 @@ public:
void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
uint *and_level, table_map usable_tables,
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);
Item *transform(Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
......
......@@ -134,6 +134,7 @@ public:
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
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;
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
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)
}
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;
SEL_TREE *ftree= 0;
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_ENTER("get_mm_tree_for_const");
if (cond->is_expensive())
DBUG_RETURN(0);
/*
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)
*/
MEM_ROOT *tmp_root= param->mem_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);
param->thd->mem_root= tmp_root;
DBUG_RETURN(tree);
}
}
table_map ref_tables= 0;
table_map param_comp= ~(param->prev_tables | param->read_tables |
param->current_table);
if (type() != Item::FUNC_ITEM)
{ // Should be a field
ref_tables= used_tables();
SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item::get_mm_tree");
if (const_item())
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) ||
(ref_tables & ~(param->prev_tables | param->read_tables)))
DBUG_RETURN(0);
DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
}
}
Item_func *cond_func= (Item_func*) this;
if (cond_func->functype() == Item_func::BETWEEN ||
cond_func->functype() == Item_func::IN_FUNC)
inv= ((Item_func_opt_neg *) cond_func)->negated;
else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0);
SEL_TREE *
Item_func_between::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
DBUG_ENTER("Item::get_mm_tree");
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param, this));
param->cond= this;
switch (cond_func->functype()) {
case Item_func::BETWEEN:
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
SEL_TREE *tree= 0;
SEL_TREE *ftree= 0;
if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{
field_item= (Item_field*) (cond_func->arguments()[0]->real_item());
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv);
Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
ftree= get_full_func_mm_tree(param, this, field_item, NULL, negated);
}
/*
Concerning the code below see the NOTES section in
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());
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
field_item, (Item*)(intptr)i, inv);
if (inv)
Item_field *field_item= (Item_field*) (arguments()[i]->real_item());
SEL_TREE *tmp= get_full_func_mm_tree(param, this, field_item,
(Item*)(intptr) i, negated);
if (negated)
{
tree= !tree ? tmp : tree_or(param, tree, tmp);
if (tree == NULL)
......@@ -8130,31 +8137,53 @@ SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
else
tree= tree_and(param, tree, tmp);
}
else if (inv)
else if (negated)
{
tree= 0;
break;
}
}
ftree = tree_and(param, ftree, tree);
break;
case Item_func::IN_FUNC:
{
Item_func_in *func=(Item_func_in*) cond_func;
if (func->key_item()->real_item()->type() != Item::FIELD_ITEM)
ftree= tree_and(param, ftree, tree);
DBUG_RETURN(ftree);
}
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);
field_item= (Item_field*) (func->key_item()->real_item());
ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv);
break;
}
case Item_func::MULT_EQUAL_FUNC:
{
Item_equal *item_equal= (Item_equal *) this;
if (!(value= item_equal->get_const()) || value->is_expensive())
Item_field *field= (Item_field*) (key_item()->real_item());
SEL_TREE *tree= get_full_func_mm_tree(param, this, field, NULL, negated);
DBUG_RETURN(tree);
}
SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
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);
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++)
{
Field *field= it.get_curr_field();
......@@ -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))
{
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);
}
}
DBUG_RETURN(ftree);
}
default:
}
DBUG_ASSERT (!ftree);
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
{
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());
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : NULL;
Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
Item *value= arg_count > 1 ? arguments()[1] : NULL;
if (value && value->is_expensive())
DBUG_RETURN(0);
if (!cond_func->arguments()[0]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv);
if (!arguments()[0]->real_item()->const_item())
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
......@@ -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
below) may succeed.
*/
if (!ftree && cond_func->have_rev_func() &&
cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
if (!ftree && have_rev_func() &&
arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
{
field_item= (Item_field*) (cond_func->arguments()[1]->real_item());
value= cond_func->arguments()[0];
Item_field *field_item= (Item_field*) (arguments()[1]->real_item());
Item *value= arguments()[0];
if (value && value->is_expensive())
DBUG_RETURN(0);
if (!cond_func->arguments()[1]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv);
}
if (!arguments()[1]->real_item()->const_item())
ftree= get_full_func_mm_tree(param, this, field_item, value, false);
}
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