Commit f6a8ec5f authored by unknown's avatar unknown

"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.


sql/item.cc:
  Added cached_field_index member to Item_ident for caching field
  position in TABLE::field array for quicker field lookup in case 
  fix_fields() is executed twice.
sql/item.h:
  Added cached_field_index member to Item_ident for caching field
  position in TABLE::field array for quicker field lookup in case 
  fix_fields() is executed twice.
sql/mysql_priv.h:
  Now find_field_in_table has one more in-out parameter which is used
  for caching field index in TABLE::field array stored for quicker
  field look up.
sql/sql_acl.cc:
  Now find_field_in_table has one more in-out parameter which is used
  for caching field index in TABLE::field array stored for quicker
  field look up.
sql/sql_base.cc:
  Optimization: Now when we are looking up Field by its name we are 
  caching its position in TABLE::field array in Item_ident::cached_field_index,
  so when we will call fix_fields() second time for this item (e.g.
  when we are re-executing prep statement) we can reuse this index
  to speed up this lookup.
sql/table.cc:
  Now we storing in TABLE::name_hash pointers to elements of 
  TABLE::field array, because this allows easily retrieve index
  of field in this array when it is looked up by its name.
sql/table.h:
  Added comment claryfying what we store in TABLE::name_hash.
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
parent 2f74974b
......@@ -26,6 +26,7 @@ bk@admin.bk
bk@mysql.r18.ru
carsten@tsort.bitbybit.dk
davida@isil.mysql.com
dlenev@brandersnatch.localdomain
dlenev@build.mysql.com
dlenev@mysql.com
gerberb@ou800.zenez.com
......
......@@ -105,7 +105,7 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par)
:changed_during_fix_field(0), db_name(db_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;
}
......@@ -117,6 +117,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
db_name(item->db_name),
table_name(item->table_name),
field_name(item->field_name),
cached_field_index(item->cached_field_index),
depended_from(item->depended_from)
{}
......
......@@ -262,6 +262,11 @@ class Item_ident :public Item
const char *db_name;
const char *table_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;
Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par);
......
......@@ -558,7 +558,8 @@ extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
TABLE_LIST **where, bool report_error);
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
#include <openssl/des.h>
struct st_des_keyblock
......
......@@ -2194,8 +2194,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1);
while ((column = column_iter++))
{
int unused_field_idx= -1;
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),
column->column.c_ptr(), table_list->alias);
......
......@@ -1790,33 +1790,44 @@ bool rm_temporary_table(enum db_type base, char *path)
#define WRONG_GRANT (Field*) -1
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;
if (table->name_hash.records)
{
if ((field=(Field*) hash_search(&table->name_hash,(byte*) name,
length)))
goto found;
}
Field **field_ptr= 0, *field;
int cached_field_index= *cached_field_index_ptr;
if (cached_field_index >= 0 && cached_field_index < table->fields &&
!my_strcasecmp(system_charset_info,
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
{
Field **ptr;
if (!(ptr=table->field))
if (!(field_ptr=table->field))
return (Field *)0;
while ((field = *ptr++))
while (*field_ptr)
{
if (!my_strcasecmp(system_charset_info, field->field_name, name))
goto found;
if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
break;
++field_ptr;
}
}
if (allow_rowid &&
!my_strcasecmp(system_charset_info, name, "_rowid") &&
(field=table->rowid_field))
goto found;
if (field_ptr && *field_ptr)
{
*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;
}
found:
if (thd->set_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,
Field *find=find_field_in_table(thd,tables->table,name,length,
test(tables->table->grant.
want_privilege),
1);
1, &(item->cached_field_index));
if (find)
{
(*where)= 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,
test(tables->table->grant.want_privilege),
allow_rowid);
allow_rowid, &(item->cached_field_index));
if (field)
{
if (field == WRONG_GRANT)
......
......@@ -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 byte* get_field_name(Field *buff,uint *length,
static byte* get_field_name(Field **buff,uint *length,
my_bool not_used __attribute__((unused)))
{
*length= (uint) strlen(buff->field_name);
return (byte*) buff->field_name;
*length= (uint) strlen((*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,
if (outparam->timestamp_field == reg_field)
outparam->timestamp_field_offset=i;
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
......
......@@ -65,7 +65,8 @@ struct st_table {
handler *file;
Field **field; /* Pointer to 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 *default_values; /* Default values for INSERT */
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