"Fix" for BUG #2050 "10 to 1 performance drop with server 4.1.1".

Actually it is not a bug but right behavior observed as pefomance 
degradation after we have forced Item_field::fix_fields() to 
re-execute each time when we are executing prep stmt.

This patch implements small optimization which heals this bad 
behavior. We are caching field position in TABLE::field array in
Item's member and are using this position for speeding up field
lookups in fix_fields() in case of its re-execution.
parent b84a9dcf
...@@ -26,6 +26,7 @@ bk@admin.bk ...@@ -26,6 +26,7 @@ bk@admin.bk
bk@mysql.r18.ru bk@mysql.r18.ru
carsten@tsort.bitbybit.dk carsten@tsort.bitbybit.dk
davida@isil.mysql.com davida@isil.mysql.com
dlenev@brandersnatch.localdomain
dlenev@build.mysql.com dlenev@build.mysql.com
dlenev@mysql.com dlenev@mysql.com
gerberb@ou800.zenez.com gerberb@ou800.zenez.com
......
...@@ -105,7 +105,7 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, ...@@ -105,7 +105,7 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par) const char *field_name_par)
:changed_during_fix_field(0), db_name(db_name_par), :changed_during_fix_field(0), db_name(db_name_par),
table_name(table_name_par), field_name(field_name_par), table_name(table_name_par), field_name(field_name_par),
depended_from(0) cached_field_index(-1), depended_from(0)
{ {
name = (char*) field_name_par; name = (char*) field_name_par;
} }
...@@ -117,6 +117,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) ...@@ -117,6 +117,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
db_name(item->db_name), db_name(item->db_name),
table_name(item->table_name), table_name(item->table_name),
field_name(item->field_name), field_name(item->field_name),
cached_field_index(item->cached_field_index),
depended_from(item->depended_from) depended_from(item->depended_from)
{} {}
......
...@@ -262,6 +262,11 @@ public: ...@@ -262,6 +262,11 @@ public:
const char *db_name; const char *db_name;
const char *table_name; const char *table_name;
const char *field_name; const char *field_name;
/*
Cached value of index for this field in table->field array, used by prep.
stmts for speeding up their re-execution, -1 if index value is not known.
*/
int cached_field_index;
st_select_lex *depended_from; st_select_lex *depended_from;
Item_ident(const char *db_name_par,const char *table_name_par, Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par); const char *field_name_par);
......
...@@ -558,7 +558,8 @@ extern const Field *not_found_field; ...@@ -558,7 +558,8 @@ extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
TABLE_LIST **where, bool report_error); TABLE_LIST **where, bool report_error);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid); bool check_grant,bool allow_rowid,
int *cached_field_index_ptr);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/des.h> #include <openssl/des.h>
struct st_des_keyblock struct st_des_keyblock
......
...@@ -2194,8 +2194,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2194,8 +2194,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1); DBUG_RETURN(-1);
while ((column = column_iter++)) while ((column = column_iter++))
{ {
int unused_field_idx= -1;
if (!find_field_in_table(thd,table,column->column.ptr(), if (!find_field_in_table(thd,table,column->column.ptr(),
column->column.length(),0,0)) column->column.length(),0,0,
&unused_field_idx))
{ {
my_error(ER_BAD_FIELD_ERROR, MYF(0), my_error(ER_BAD_FIELD_ERROR, MYF(0),
column->column.c_ptr(), table_list->alias); column->column.c_ptr(), table_list->alias);
......
...@@ -1790,33 +1790,44 @@ bool rm_temporary_table(enum db_type base, char *path) ...@@ -1790,33 +1790,44 @@ bool rm_temporary_table(enum db_type base, char *path)
#define WRONG_GRANT (Field*) -1 #define WRONG_GRANT (Field*) -1
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grants, bool allow_rowid) bool check_grants, bool allow_rowid,
int *cached_field_index_ptr)
{ {
Field *field; Field **field_ptr= 0, *field;
if (table->name_hash.records) int cached_field_index= *cached_field_index_ptr;
{
if ((field=(Field*) hash_search(&table->name_hash,(byte*) name, if (cached_field_index >= 0 && cached_field_index < table->fields &&
length))) !my_strcasecmp(system_charset_info,
goto found; table->field[cached_field_index]->field_name, name))
} field_ptr= table->field + cached_field_index;
else if (table->name_hash.records)
field_ptr= (Field**)hash_search(&table->name_hash,(byte*) name,
length);
else else
{ {
Field **ptr; if (!(field_ptr=table->field))
if (!(ptr=table->field))
return (Field *)0; return (Field *)0;
while ((field = *ptr++)) while (*field_ptr)
{ {
if (!my_strcasecmp(system_charset_info, field->field_name, name)) if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
goto found; break;
++field_ptr;
} }
} }
if (allow_rowid &&
!my_strcasecmp(system_charset_info, name, "_rowid") && if (field_ptr && *field_ptr)
(field=table->rowid_field)) {
goto found; *cached_field_index_ptr= field_ptr - table->field;
field= *field_ptr;
}
else
{
if (!allow_rowid ||
my_strcasecmp(system_charset_info, name, "_rowid") ||
!(field=table->rowid_field))
return (Field*) 0; return (Field*) 0;
}
found:
if (thd->set_query_id) if (thd->set_query_id)
{ {
if (field->query_id != thd->query_id) if (field->query_id != thd->query_id)
...@@ -1895,7 +1906,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -1895,7 +1906,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *find=find_field_in_table(thd,tables->table,name,length, Field *find=find_field_in_table(thd,tables->table,name,length,
test(tables->table->grant. test(tables->table->grant.
want_privilege), want_privilege),
1); 1, &(item->cached_field_index));
if (find) if (find)
{ {
(*where)= tables; (*where)= tables;
...@@ -1952,7 +1963,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -1952,7 +1963,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *field=find_field_in_table(thd,tables->table,name,length, Field *field=find_field_in_table(thd,tables->table,name,length,
test(tables->table->grant.want_privilege), test(tables->table->grant.want_privilege),
allow_rowid); allow_rowid, &(item->cached_field_index));
if (field) if (field)
{ {
if (field == WRONG_GRANT) if (field == WRONG_GRANT)
......
...@@ -30,11 +30,11 @@ static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, ...@@ -30,11 +30,11 @@ static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
static uint find_field(TABLE *form,uint start,uint length); static uint find_field(TABLE *form,uint start,uint length);
static byte* get_field_name(Field *buff,uint *length, static byte* get_field_name(Field **buff,uint *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__((unused)))
{ {
*length= (uint) strlen(buff->field_name); *length= (uint) strlen((*buff)->field_name);
return (byte*) buff->field_name; return (byte*) (*buff)->field_name;
} }
/* /*
...@@ -479,7 +479,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -479,7 +479,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (outparam->timestamp_field == reg_field) if (outparam->timestamp_field == reg_field)
outparam->timestamp_field_offset=i; outparam->timestamp_field_offset=i;
if (use_hash) if (use_hash)
(void) my_hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail
} }
*field_ptr=0; // End marker *field_ptr=0; // End marker
......
...@@ -65,7 +65,8 @@ struct st_table { ...@@ -65,7 +65,8 @@ struct st_table {
handler *file; handler *file;
Field **field; /* Pointer to fields */ Field **field; /* Pointer to fields */
Field_blob **blob_field; /* Pointer to blob fields */ Field_blob **blob_field; /* Pointer to blob fields */
HASH name_hash; /* hash of field names */ /* hash of field names (contains pointers to elements of field array) */
HASH name_hash;
byte *record[2]; /* Pointer to records */ byte *record[2]; /* Pointer to records */
byte *default_values; /* Default values for INSERT */ byte *default_values; /* Default values for INSERT */
byte *insert_values; /* used by INSERT ... UPDATE */ byte *insert_values; /* used by INSERT ... UPDATE */
......
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