Commit 37a316c0 authored by Dmitry Shulga's avatar Dmitry Shulga Committed by Sergei Golubchik

MDEV-29988: Major performance regression with 10.6.11

The idea is to put Item_direct_ref_to_item as a transparent and
permanent wrapper before a string which require conversion.
So that Item_direct_ref_to_item would be the only place where
the pointer to the string item is stored, this pointer can be changed
and restored during PS execution as needed. And if any permanent
(subquery) optimization would need a pointer to the item,
it'll use a pointer to the Item_direct_ref_to_item - which is
a permanent item and won't go away.
parent a9b31b08
......@@ -5700,3 +5700,18 @@ EXECUTE stmt USING 'd';
EXECUTE stmt USING 'd';
300
DROP TABLE t1, t2, t3;
set @@max_session_mem_used=default;
create table t (a varchar(10)) character set utf8;
insert into t values ('');
prepare stmt from "select 1 from t where a = ?";
set @@max_session_mem_used=(select memory_used*2 from information_schema.processlist where id=connection_id());
deallocate prepare stmt;
drop table t;
set @@max_session_mem_used=default;
create table t (a varchar(10)) character set utf8;
insert into t values ('');
prepare stmt from "select 1 from t where a = 'a'";
set @@max_session_mem_used=(select memory_used*2 from information_schema.processlist where id=connection_id());
deallocate prepare stmt;
drop table t;
set @@max_session_mem_used=default;
......@@ -5116,3 +5116,38 @@ EXECUTE stmt USING 'b';
EXECUTE stmt USING 'd';
EXECUTE stmt USING 'd';
DROP TABLE t1, t2, t3;
set @@max_session_mem_used=default;
create table t (a varchar(10)) character set utf8;
insert into t values ('');
prepare stmt from "select 1 from t where a = ?";
set @@max_session_mem_used=(select memory_used*2 from information_schema.processlist where id=connection_id());
let $run= 1000;
disable_result_log;
disable_query_log;
while ($run) {
execute stmt using repeat('x',10000);
dec $run;
}
enable_result_log;
enable_query_log;
deallocate prepare stmt;
drop table t;
set @@max_session_mem_used=default;
create table t (a varchar(10)) character set utf8;
insert into t values ('');
prepare stmt from "select 1 from t where a = 'a'";
set @@max_session_mem_used=(select memory_used*2 from information_schema.processlist where id=connection_id());
let $run= 1000;
disable_result_log;
disable_query_log;
while ($run) {
execute stmt;
dec $run;
}
enable_result_log;
enable_query_log;
deallocate prepare stmt;
drop table t;
set @@max_session_mem_used=default;
......@@ -41,6 +41,7 @@
// find_item_in_list,
// RESOLVED_AGAINST_ALIAS, ...
#include "sql_expression_cache.h"
#include "sql_lex.h" // empty_clex_str
const String my_null_string("NULL", 4, default_charset_info);
const String my_default_string("DEFAULT", 7, default_charset_info);
......@@ -1401,13 +1402,11 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
Item *conv= example->safe_charset_converter(thd, tocs);
if (conv == example)
return this;
Item_cache *cache;
if (!conv || conv->fix_fields(thd, (Item **) NULL) ||
unlikely(!(cache= new (thd->mem_root) Item_cache_str(thd, conv))))
if (!conv || conv->fix_fields(thd, (Item **) NULL))
return NULL; // Safe conversion is not possible, or OEM
cache->setup(thd, conv);
cache->fixed= false; // Make Item::fix_fields() happy
return cache;
setup(thd, conv);
thd->change_item_tree(&example, conv);
return this;
}
......@@ -2782,7 +2781,6 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
safe_args[1]= args[item_sep];
}
bool res= FALSE;
uint i;
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
......@@ -2802,19 +2800,31 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
args[item_sep]= safe_args[1];
}
my_coll_agg_error(args, nargs, fname, item_sep);
res= TRUE;
break; // we cannot return here, we need to restore "arena".
return TRUE;
}
thd->change_item_tree(arg, conv);
if (conv->fix_fields(thd, arg))
return TRUE;
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
if (arena)
{
Item_direct_ref_to_item *ref=
new (thd->mem_root) Item_direct_ref_to_item(thd, *arg);
if ((ref == NULL) || ref->fix_fields(thd, (Item **)&ref))
{
res= TRUE;
break; // we cannot return here, we need to restore "arena".
thd->restore_active_arena(arena, &backup);
return TRUE;
}
*arg= ref;
thd->restore_active_arena(arena, &backup);
ref->change_item(thd, conv);
}
return res;
else
thd->change_item_tree(arg, conv);
}
return FALSE;
}
......@@ -10952,3 +10962,45 @@ void Item::register_in(THD *thd)
next= thd->free_list;
thd->free_list= this;
}
Item_direct_ref_to_item::Item_direct_ref_to_item(THD *thd, Item *item)
: Item_direct_ref(thd, NULL, NULL, "", &empty_clex_str, FALSE)
{
m_item= item;
ref= (Item**)&m_item;
}
bool Item_direct_ref_to_item::fix_fields(THD *thd, Item **)
{
DBUG_ASSERT(m_item != NULL);
if (m_item->fix_fields_if_needed_for_scalar(thd, ref))
return TRUE;
set_properties();
return FALSE;
}
void Item_direct_ref_to_item::print(String *str, enum_query_type query_type)
{
m_item->print(str, query_type);
}
Item *Item_direct_ref_to_item::safe_charset_converter(THD *thd,
CHARSET_INFO *tocs)
{
Item *conv= m_item->safe_charset_converter(thd, tocs);
if (conv != m_item)
{
if (conv== NULL || conv->fix_fields(thd, &conv))
return NULL;
change_item(thd, conv);
}
return this;
}
void Item_direct_ref_to_item::change_item(THD *thd, Item *i)
{
DBUG_ASSERT(i->fixed);
thd->change_item_tree(ref, i);
set_properties();
}
......@@ -6890,4 +6890,97 @@ inline void Virtual_column_info::print(String* str)
expr->print_for_table_def(str);
}
class Item_direct_ref_to_item : public Item_direct_ref
{
Item *m_item;
public:
Item_direct_ref_to_item(THD *thd, Item *item);
void change_item(THD *thd, Item *);
bool fix_fields(THD *thd, Item **it);
void print(String *str, enum_query_type query_type);
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
Item *get_tmp_table_item(THD *thd)
{ return m_item->get_tmp_table_item(thd); }
Item *get_copy(THD *thd)
{ return m_item->get_copy(thd); }
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
COND_EQUAL **cond_equal_ref)
{
return m_item->build_equal_items(thd, inherited, link_item_fields,
cond_equal_ref);
}
const char *full_name() const { return m_item->full_name(); }
void make_send_field(THD *thd, Send_field *field)
{ m_item->make_send_field(thd, field); }
bool eq(const Item *item, bool binary_cmp) const
{
Item *it= ((Item *) item)->real_item();
return m_item->eq(it, binary_cmp);
}
void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge)
{ m_item->fix_after_pullout(new_parent, &m_item, merge); }
void save_val(Field *to)
{ return m_item->save_val(to); }
void save_result(Field *to)
{ return m_item->save_result(to); }
int save_in_field(Field *to, bool no_conversions)
{ return m_item->save_in_field(to, no_conversions); }
const Type_handler *type_handler() const { return m_item->type_handler(); }
table_map used_tables() const { return m_item->used_tables(); }
void update_used_tables()
{ m_item->update_used_tables(); }
bool const_item() const { return m_item->const_item(); }
table_map not_null_tables() const { return m_item->not_null_tables(); }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
{
return m_item->walk(processor, walk_subquery, arg) ||
(this->*processor)(arg);
}
bool enumerate_field_refs_processor(void *arg)
{ return m_item->enumerate_field_refs_processor(arg); }
Item_field *field_for_view_update()
{ return m_item->field_for_view_update(); }
/* Row emulation: forwarding of ROW-related calls to orig_item */
uint cols() const
{ return m_item->cols(); }
Item* element_index(uint i)
{ return this; }
Item** addr(uint i)
{ return &m_item; }
bool check_cols(uint c)
{ return Item::check_cols(c); }
bool null_inside()
{ return m_item->null_inside(); }
void bring_value()
{}
Item_equal *get_item_equal() { return m_item->get_item_equal(); }
void set_item_equal(Item_equal *item_eq) { m_item->set_item_equal(item_eq); }
Item_equal *find_item_equal(COND_EQUAL *cond_equal)
{ return m_item->find_item_equal(cond_equal); }
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{ return m_item->propagate_equal_fields(thd, ctx, cond); }
Item *replace_equal_field(THD *thd, uchar *arg)
{ return m_item->replace_equal_field(thd, arg); }
bool excl_dep_on_table(table_map tab_map)
{ return m_item->excl_dep_on_table(tab_map); }
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{ return m_item->excl_dep_on_grouping_fields(sel); }
bool is_expensive() { return m_item->is_expensive(); }
Item* build_clone(THD *thd) { return get_copy(thd); }
/*
This processor states that this is safe for virtual columns
(because this Item transparency)
*/
bool check_vcol_func_processor(void *arg) { return FALSE;}
};
#endif /* SQL_ITEM_INCLUDED */
......@@ -539,7 +539,7 @@ bool Item_func_in::create_value_list_for_tvc(THD *thd,
if (is_list_of_rows)
{
Item_row *row_list= (Item_row *)(args[i]->build_clone(thd));
Item_row *row_list= (Item_row *)(args[i]);
if (!row_list)
return true;
......@@ -564,8 +564,7 @@ bool Item_func_in::create_value_list_for_tvc(THD *thd,
sprintf(col_name, "_col_%i", 1);
args[i]->set_name(thd, col_name, strlen(col_name), thd->charset());
}
Item *arg_clone= args[i]->build_clone(thd);
if (!arg_clone || tvc_value->push_back(arg_clone))
if (tvc_value->push_back(args[i]))
return true;
}
......
......@@ -3010,7 +3010,7 @@ class Vcol_expr_context
bool inited;
THD *thd;
TABLE *table;
Query_arena backup_arena;
Query_arena backup_arena, *stmt_arena;
table_map old_map;
Security_context *save_security_ctx;
sql_mode_t save_sql_mode;
......@@ -3020,6 +3020,7 @@ class Vcol_expr_context
inited(false),
thd(_thd),
table(_table),
stmt_arena(thd->stmt_arena),
old_map(table->map),
save_security_ctx(thd->security_ctx),
save_sql_mode(thd->variables.sql_mode) {}
......@@ -3040,6 +3041,7 @@ bool Vcol_expr_context::init()
thd->security_ctx= tl->security_ctx;
thd->set_n_backup_active_arena(table->expr_arena, &backup_arena);
thd->stmt_arena= thd;
inited= true;
return false;
......@@ -3053,6 +3055,7 @@ Vcol_expr_context::~Vcol_expr_context()
thd->security_ctx= save_security_ctx;
thd->restore_active_arena(table->expr_arena, &backup_arena);
thd->variables.sql_mode= save_sql_mode;
thd->stmt_arena= stmt_arena;
}
......
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