Fixed bug mdev-3979.
Made allocation of memory for statistical data in a table share to be thread safe. This memory is now allocated in a special MEM_ROOT that is created for each table share.
This commit is contained in:
parent
e44253a125
commit
01dca17a9c
@ -3143,16 +3143,6 @@ retry_share:
|
||||
while (table_cache_count > table_cache_size && unused_tables)
|
||||
free_cache_entry(unused_tables);
|
||||
|
||||
if (get_use_stat_tables_mode(thd) > NEVER)
|
||||
{
|
||||
if (share->table_category != TABLE_CATEGORY_SYSTEM)
|
||||
{
|
||||
if (!share->stats_can_be_read &&
|
||||
!alloc_statistics_for_table_share(thd, share, TRUE))
|
||||
share->stats_can_be_read= TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
|
||||
/* make a new table */
|
||||
@ -4638,22 +4628,24 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
|
||||
if (get_use_stat_tables_mode(thd) > NEVER && tables->table)
|
||||
{
|
||||
TABLE_SHARE *table_share= tables->table->s;
|
||||
if (table_share && table_share->table_category != TABLE_CATEGORY_SYSTEM)
|
||||
if (table_share && table_share->table_category == TABLE_CATEGORY_USER &&
|
||||
table_share->tmp_table == NO_TMP_TABLE)
|
||||
{
|
||||
if (!table_share->stats_can_be_read &&
|
||||
!alloc_statistics_for_table_share(thd, table_share, FALSE))
|
||||
{
|
||||
KEY *key_info= table_share->key_info;
|
||||
KEY *key_info_end= key_info + table_share->keys;
|
||||
KEY *table_key_info= tables->table->key_info;
|
||||
for ( ; key_info < key_info_end; key_info++, table_key_info++)
|
||||
table_key_info->read_stats= key_info->read_stats;
|
||||
Field **field_ptr= table_share->field;
|
||||
Field **table_field_ptr= tables->table->field;
|
||||
for ( ; *field_ptr; field_ptr++, table_field_ptr++)
|
||||
(*table_field_ptr)->read_stats= (*field_ptr)->read_stats;
|
||||
|
||||
table_share->stats_can_be_read= TRUE;
|
||||
if (table_share->stats_cb.stats_can_be_read ||
|
||||
!alloc_statistics_for_table_share(thd, table_share, FALSE))
|
||||
{
|
||||
if (table_share->stats_cb.stats_can_be_read)
|
||||
{
|
||||
KEY *key_info= table_share->key_info;
|
||||
KEY *key_info_end= key_info + table_share->keys;
|
||||
KEY *table_key_info= tables->table->key_info;
|
||||
for ( ; key_info < key_info_end; key_info++, table_key_info++)
|
||||
table_key_info->read_stats= key_info->read_stats;
|
||||
Field **field_ptr= table_share->field;
|
||||
Field **table_field_ptr= tables->table->field;
|
||||
for ( ; *field_ptr; field_ptr++, table_field_ptr++)
|
||||
(*table_field_ptr)->read_stats= (*field_ptr)->read_stats;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4895,7 +4887,7 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize temporary MEM_ROOT for new .FRM parsing. Do not allocate
|
||||
Initialize temporary MEM_ROOT for new .FRM parsing. Do not alloctaate
|
||||
anything yet, to avoid penalty for statements which don't use views
|
||||
and thus new .FRM format.
|
||||
*/
|
||||
|
@ -158,34 +158,6 @@ inline int open_single_stat_table(THD *thd, TABLE_LIST *table,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@details
|
||||
If the value of the parameter is_safe is TRUE then the function
|
||||
just copies the address pointed by the parameter src into the memory
|
||||
pointed by the parameter dest. Otherwise the function performs the
|
||||
following statement as an atomic action:
|
||||
if (*dest == NULL) { *dest= *src; }
|
||||
i.e. the same copying is performed only if *dest is NULL.
|
||||
*/
|
||||
|
||||
static
|
||||
inline void store_address_if_first(void **dest, void **src, bool is_safe)
|
||||
{
|
||||
if (is_safe)
|
||||
{
|
||||
if (!*dest)
|
||||
memcpy(dest, src, sizeof(void *));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *null= NULL;
|
||||
my_atomic_rwlock_wrlock(&statistics_lock);
|
||||
my_atomic_casptr(dest, (void **) &null, *src)
|
||||
my_atomic_rwlock_wrunlock(&statistics_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The class Column_statistics_collected is a helper class used to collect
|
||||
statistics on a table column. The class is derived directly from
|
||||
@ -737,15 +709,16 @@ public:
|
||||
|
||||
void get_stat_values()
|
||||
{
|
||||
table_share->read_stats->cardinality_is_null= TRUE;
|
||||
table_share->read_stats->cardinality= 0;
|
||||
Table_statistics *read_stats= table_share->stats_cb.table_stats;
|
||||
read_stats->cardinality_is_null= TRUE;
|
||||
read_stats->cardinality= 0;
|
||||
if (find_stat())
|
||||
{
|
||||
Field *stat_field= stat_table->field[TABLE_STAT_CARDINALITY];
|
||||
if (!stat_field->is_null())
|
||||
{
|
||||
table_share->read_stats->cardinality_is_null= FALSE;
|
||||
table_share->read_stats->cardinality= stat_field->val_int();
|
||||
read_stats->cardinality_is_null= FALSE;
|
||||
read_stats->cardinality= stat_field->val_int();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1547,28 +1520,22 @@ public:
|
||||
*/
|
||||
|
||||
static
|
||||
void create_min_max_stistical_fields_for_table(TABLE *table)
|
||||
void create_min_max_statistical_fields_for_table(TABLE *table)
|
||||
{
|
||||
Field *table_field;
|
||||
Field **field_ptr;
|
||||
uchar *record;
|
||||
uint rec_buff_length= table->s->rec_buff_length;
|
||||
|
||||
for (field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
if ((table->collected_stats->min_max_record_buffers=
|
||||
(uchar *) alloc_root(&table->mem_root, 2*rec_buff_length)))
|
||||
{
|
||||
table_field= *field_ptr;
|
||||
table_field->collected_stats->max_value=
|
||||
table_field->collected_stats->min_value= NULL;
|
||||
}
|
||||
uchar *record= table->collected_stats->min_max_record_buffers;
|
||||
memset(record, 0, 2*rec_buff_length);
|
||||
|
||||
if ((record= (uchar *) alloc_root(&table->mem_root, 2*rec_buff_length)))
|
||||
{
|
||||
for (uint i=0; i < 2; i++, record+= rec_buff_length)
|
||||
{
|
||||
for (field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
for (Field **field_ptr= table->field; *field_ptr; field_ptr++)
|
||||
{
|
||||
Field *fld;
|
||||
table_field= *field_ptr;
|
||||
Field *table_field= *field_ptr;
|
||||
my_ptrdiff_t diff= record-table->record[0];
|
||||
if (!bitmap_is_set(table->read_set, table_field->field_index))
|
||||
continue;
|
||||
@ -1615,41 +1582,40 @@ void create_min_max_stistical_fields_for_table(TABLE *table)
|
||||
*/
|
||||
|
||||
static
|
||||
void create_min_max_stistical_fields_for_table_share(THD *thd,
|
||||
TABLE_SHARE *table_share,
|
||||
bool is_safe)
|
||||
void create_min_max_statistical_fields_for_table_share(THD *thd,
|
||||
TABLE_SHARE *table_share)
|
||||
{
|
||||
Field *table_field;
|
||||
Field **field_ptr;
|
||||
uchar *record;
|
||||
TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb;
|
||||
Table_statistics *stats= stats_cb->table_stats;
|
||||
|
||||
if (stats->min_max_record_buffers)
|
||||
return;
|
||||
|
||||
uint rec_buff_length= table_share->rec_buff_length;
|
||||
|
||||
for (field_ptr= table_share->field; *field_ptr; field_ptr++)
|
||||
if ((stats->min_max_record_buffers=
|
||||
(uchar *) alloc_root(&stats_cb->mem_root, 2*rec_buff_length)))
|
||||
{
|
||||
table_field= *field_ptr;
|
||||
table_field->read_stats->max_value=
|
||||
table_field->read_stats->min_value= NULL;
|
||||
}
|
||||
uchar *record= stats->min_max_record_buffers;
|
||||
memset(record, 0, 2*rec_buff_length);
|
||||
|
||||
if ((record= (uchar *) alloc_root(&table_share->mem_root, 2*rec_buff_length)))
|
||||
{
|
||||
for (uint i=0; i < 2; i++, record+= rec_buff_length)
|
||||
{
|
||||
for (field_ptr= table_share->field; *field_ptr; field_ptr++)
|
||||
for (Field **field_ptr= table_share->field; *field_ptr; field_ptr++)
|
||||
{
|
||||
Field *fld;
|
||||
table_field= *field_ptr;
|
||||
Field *table_field= *field_ptr;
|
||||
my_ptrdiff_t diff= record - table_share->default_values;
|
||||
if (!(fld= table_field->clone(&table_share->mem_root, diff)))
|
||||
if (!(fld= table_field->clone(&stats_cb->mem_root, diff)))
|
||||
continue;
|
||||
store_address_if_first(i == 0 ?
|
||||
(void **) &table_field->read_stats->min_value :
|
||||
(void **) &table_field->read_stats->max_value,
|
||||
(void **) &fld,
|
||||
is_safe);
|
||||
if (i == 0)
|
||||
table_field->read_stats->min_value= fld;
|
||||
else
|
||||
table_field->read_stats->max_value= fld;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1684,6 +1650,7 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
|
||||
|
||||
DBUG_ENTER("alloc_statistics_for_table");
|
||||
|
||||
|
||||
Table_statistics *table_stats=
|
||||
(Table_statistics *) alloc_root(&table->mem_root,
|
||||
sizeof(Table_statistics));
|
||||
@ -1692,7 +1659,7 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
|
||||
Column_statistics_collected *column_stats=
|
||||
(Column_statistics_collected *) alloc_root(&table->mem_root,
|
||||
sizeof(Column_statistics_collected) *
|
||||
fields);
|
||||
(fields+1));
|
||||
|
||||
uint keys= table->s->keys;
|
||||
Index_statistics *index_stats=
|
||||
@ -1711,10 +1678,14 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
|
||||
table_stats->index_stats= index_stats;
|
||||
table_stats->idx_avg_frequency= idx_avg_frequency;
|
||||
|
||||
memset(column_stats, 0, sizeof(Column_statistics) * fields);
|
||||
memset(column_stats, 0, sizeof(Column_statistics) * (fields+1));
|
||||
|
||||
for (field_ptr= table->field; *field_ptr; field_ptr++, column_stats++)
|
||||
{
|
||||
(*field_ptr)->collected_stats= column_stats;
|
||||
(*field_ptr)->collected_stats->max_value= NULL;
|
||||
(*field_ptr)->collected_stats->min_value= NULL;
|
||||
}
|
||||
|
||||
memset(idx_avg_frequency, 0, sizeof(ulong) * key_parts);
|
||||
|
||||
@ -1728,12 +1699,54 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
|
||||
idx_avg_frequency+= key_info->ext_key_parts;
|
||||
}
|
||||
|
||||
create_min_max_stistical_fields_for_table(table);
|
||||
create_min_max_statistical_fields_for_table(table);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Check whether any persistent statistics for the processed command is needed
|
||||
|
||||
@param
|
||||
thd The thread handle
|
||||
|
||||
@details
|
||||
The function checks whether any persitent statistics for the processed
|
||||
command is needed to be read.
|
||||
|
||||
@retval
|
||||
TRUE statistics is needed to be read
|
||||
@retval
|
||||
FALSE Otherwise
|
||||
*/
|
||||
|
||||
static
|
||||
inline bool statistics_for_command_is_needed(THD *thd)
|
||||
{
|
||||
if (thd->bootstrap || thd->variables.use_stat_tables == NEVER)
|
||||
return FALSE;
|
||||
|
||||
switch(thd->lex->sql_command) {
|
||||
case SQLCOM_SELECT:
|
||||
case SQLCOM_INSERT:
|
||||
case SQLCOM_INSERT_SELECT:
|
||||
case SQLCOM_UPDATE:
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
case SQLCOM_DELETE:
|
||||
case SQLCOM_DELETE_MULTI:
|
||||
case SQLCOM_REPLACE:
|
||||
case SQLCOM_REPLACE_SELECT:
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Allocate memory for the statistical data used by a table share
|
||||
@ -1772,6 +1785,11 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
|
||||
Here the second and the third threads try to allocate the memory for
|
||||
statistical data at the same time. The precautions are taken to
|
||||
guarantee the correctness of the allocation.
|
||||
|
||||
@note
|
||||
Currently the function always is called with the parameter is_safe set
|
||||
to FALSE.
|
||||
|
||||
*/
|
||||
|
||||
int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share,
|
||||
@ -1779,70 +1797,111 @@ int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share,
|
||||
{
|
||||
|
||||
Field **field_ptr;
|
||||
uint cnt= 0;
|
||||
KEY *key_info, *end;
|
||||
TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb;
|
||||
|
||||
DBUG_ENTER("alloc_statistics_for_table_share");
|
||||
|
||||
DEBUG_SYNC(thd, "statistics_mem_alloc_start1");
|
||||
DEBUG_SYNC(thd, "statistics_mem_alloc_start2");
|
||||
|
||||
Table_statistics *table_stats=
|
||||
(Table_statistics *) alloc_root(&table_share->mem_root,
|
||||
sizeof(Table_statistics));
|
||||
if (!statistics_for_command_is_needed(thd))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!is_safe)
|
||||
mysql_mutex_lock(&table_share->LOCK_ha_data);
|
||||
|
||||
if (stats_cb->stats_can_be_read)
|
||||
{
|
||||
if (!is_safe)
|
||||
mysql_mutex_unlock(&table_share->LOCK_ha_data);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
Table_statistics *table_stats= stats_cb->table_stats;
|
||||
if (!table_stats)
|
||||
DBUG_RETURN(1);
|
||||
memset(table_stats, 0, sizeof(Table_statistics));
|
||||
store_address_if_first((void **) &table_share->read_stats,
|
||||
(void **) &table_stats, is_safe);
|
||||
table_stats= table_share->read_stats;
|
||||
{
|
||||
table_stats= (Table_statistics *) alloc_root(&stats_cb->mem_root,
|
||||
sizeof(Table_statistics));
|
||||
if (!table_stats)
|
||||
{
|
||||
if (!is_safe)
|
||||
mysql_mutex_unlock(&table_share->LOCK_ha_data);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
memset(table_stats, 0, sizeof(Table_statistics));
|
||||
stats_cb->table_stats= table_stats;
|
||||
}
|
||||
|
||||
for (field_ptr= table_share->field; *field_ptr; field_ptr++, cnt++) ;
|
||||
Column_statistics *column_stats=
|
||||
(Column_statistics *) alloc_root(&table_share->mem_root,
|
||||
sizeof(Column_statistics) * cnt);
|
||||
uint fields= table_share->fields;
|
||||
Column_statistics *column_stats= table_stats->column_stats;
|
||||
if (!column_stats)
|
||||
DBUG_RETURN(1);
|
||||
memset(column_stats, 0, sizeof(Column_statistics) * cnt);
|
||||
store_address_if_first((void **) &table_stats->column_stats,
|
||||
(void **) &column_stats, is_safe);
|
||||
column_stats= table_stats->column_stats;
|
||||
|
||||
for (field_ptr= table_share->field; *field_ptr; field_ptr++, column_stats++)
|
||||
(*field_ptr)->read_stats= column_stats;
|
||||
{
|
||||
column_stats= (Column_statistics *) alloc_root(&stats_cb->mem_root,
|
||||
sizeof(Column_statistics) *
|
||||
(fields+1));
|
||||
if (column_stats)
|
||||
{
|
||||
memset(column_stats, 0, sizeof(Column_statistics) * (fields+1));
|
||||
table_stats->column_stats= column_stats;
|
||||
for (field_ptr= table_share->field;
|
||||
*field_ptr;
|
||||
field_ptr++, column_stats++)
|
||||
{
|
||||
(*field_ptr)->read_stats= column_stats;
|
||||
(*field_ptr)->read_stats->min_value= NULL;
|
||||
(*field_ptr)->read_stats->max_value= NULL;
|
||||
}
|
||||
create_min_max_statistical_fields_for_table_share(thd, table_share);
|
||||
}
|
||||
}
|
||||
|
||||
uint keys= table_share->keys;
|
||||
Index_statistics *index_stats=
|
||||
(Index_statistics *) alloc_root(&table_share->mem_root,
|
||||
sizeof(Index_statistics) * keys);
|
||||
Index_statistics *index_stats= table_stats->index_stats;
|
||||
if (!index_stats)
|
||||
DBUG_RETURN(1);
|
||||
memset(index_stats, 0, sizeof(Index_statistics) * keys);
|
||||
store_address_if_first((void **) &table_stats->index_stats,
|
||||
(void **) &index_stats, is_safe);
|
||||
index_stats= table_stats->index_stats;
|
||||
{
|
||||
index_stats= (Index_statistics *) alloc_root(&stats_cb->mem_root,
|
||||
sizeof(Index_statistics) *
|
||||
keys);
|
||||
if (index_stats)
|
||||
{
|
||||
table_stats->index_stats= index_stats;
|
||||
for (key_info= table_share->key_info, end= key_info + keys;
|
||||
key_info < end;
|
||||
key_info++, index_stats++)
|
||||
{
|
||||
key_info->read_stats= index_stats;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint key_parts= table_share->ext_key_parts;
|
||||
ulong *idx_avg_frequency= (ulong*) alloc_root(&table_share->mem_root,
|
||||
sizeof(ulong) * key_parts);
|
||||
ulong *idx_avg_frequency= table_stats->idx_avg_frequency;
|
||||
if (!idx_avg_frequency)
|
||||
DBUG_RETURN(1);
|
||||
memset(idx_avg_frequency, 0, sizeof(ulong) * key_parts);
|
||||
store_address_if_first((void **) &table_stats->idx_avg_frequency,
|
||||
(void **) &idx_avg_frequency, is_safe);
|
||||
idx_avg_frequency= table_stats->idx_avg_frequency;
|
||||
|
||||
KEY *key_info, *end;
|
||||
for (key_info= table_share->key_info, end= key_info + table_share->keys;
|
||||
key_info < end;
|
||||
key_info++, index_stats++)
|
||||
{
|
||||
key_info->read_stats= index_stats;
|
||||
key_info->read_stats->init_avg_frequency(idx_avg_frequency);
|
||||
idx_avg_frequency+= key_info->ext_key_parts;
|
||||
idx_avg_frequency= (ulong*) alloc_root(&stats_cb->mem_root,
|
||||
sizeof(ulong) * key_parts);
|
||||
if (idx_avg_frequency)
|
||||
{
|
||||
memset(idx_avg_frequency, 0, sizeof(ulong) * key_parts);
|
||||
table_stats->idx_avg_frequency= idx_avg_frequency;
|
||||
for (key_info= table_share->key_info, end= key_info + keys;
|
||||
key_info < end;
|
||||
key_info++)
|
||||
{
|
||||
key_info->read_stats->init_avg_frequency(idx_avg_frequency);
|
||||
idx_avg_frequency+= key_info->ext_key_parts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_min_max_stistical_fields_for_table_share(thd, table_share, is_safe);
|
||||
|
||||
|
||||
if (column_stats && index_stats && idx_avg_frequency)
|
||||
stats_cb->stats_can_be_read= TRUE;
|
||||
|
||||
if (!is_safe)
|
||||
mysql_mutex_unlock(&table_share->LOCK_ha_data);
|
||||
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -2382,6 +2441,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
||||
}
|
||||
|
||||
/* Read statistics from the statistical table index_stats */
|
||||
Table_statistics *read_stats= table_share->stats_cb.table_stats;
|
||||
stat_table= stat_tables[INDEX_STAT].table;
|
||||
Index_stat index_stat(stat_table, table);
|
||||
for (key_info= table_share->key_info,
|
||||
@ -2402,7 +2462,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
||||
KEY *pk_key_info= table_share->key_info + table_share->primary_key;
|
||||
uint k= key_info->key_parts;
|
||||
uint pk_parts= pk_key_info->key_parts;
|
||||
ha_rows n_rows= table_share->read_stats->cardinality;
|
||||
ha_rows n_rows= read_stats->cardinality;
|
||||
double k_dist= n_rows / key_info->read_stats->get_avg_frequency(k-1);
|
||||
uint m= 0;
|
||||
for (uint j= 0; j < pk_parts; j++)
|
||||
@ -2429,8 +2489,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
||||
for (uint l= k; l < k + m; l++)
|
||||
{
|
||||
double avg_frequency= key_info->read_stats->get_avg_frequency(l);
|
||||
if (avg_frequency == 0 ||
|
||||
table_share->read_stats->cardinality_is_null)
|
||||
if (avg_frequency == 0 || read_stats->cardinality_is_null)
|
||||
avg_frequency= 1;
|
||||
else if (avg_frequency > 1)
|
||||
{
|
||||
@ -2468,26 +2527,11 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
|
||||
static
|
||||
bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
if (thd->bootstrap || thd->variables.use_stat_tables == 0)
|
||||
return FALSE;
|
||||
|
||||
if (!tables)
|
||||
return FALSE;
|
||||
|
||||
switch(thd->lex->sql_command) {
|
||||
case SQLCOM_SELECT:
|
||||
case SQLCOM_INSERT:
|
||||
case SQLCOM_INSERT_SELECT:
|
||||
case SQLCOM_UPDATE:
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
case SQLCOM_DELETE:
|
||||
case SQLCOM_DELETE_MULTI:
|
||||
case SQLCOM_REPLACE:
|
||||
case SQLCOM_REPLACE_SELECT:
|
||||
break;
|
||||
default:
|
||||
if (!statistics_for_command_is_needed(thd))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
Do not read statistics for any query over non-user tables.
|
||||
@ -2499,7 +2543,9 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables)
|
||||
if (!tl->is_view_or_derived() && tl->table)
|
||||
{
|
||||
TABLE_SHARE *table_share= tl->table->s;
|
||||
if (table_share && table_share->table_category != TABLE_CATEGORY_USER)
|
||||
if (table_share &&
|
||||
(table_share->table_category != TABLE_CATEGORY_USER ||
|
||||
table_share->tmp_table != NO_TMP_TABLE))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -2510,8 +2556,8 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
TABLE_SHARE *table_share= tl->table->s;
|
||||
if (table_share &&
|
||||
table_share->stats_can_be_read &&
|
||||
!table_share->stats_is_read)
|
||||
table_share->stats_cb.stats_can_be_read &&
|
||||
!table_share->stats_cb.stats_is_read)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -2566,11 +2612,11 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
TABLE_SHARE *table_share= tl->table->s;
|
||||
if (table_share &&
|
||||
table_share->stats_can_be_read &&
|
||||
!table_share->stats_is_read)
|
||||
table_share->stats_cb.stats_can_be_read &&
|
||||
!table_share->stats_cb.stats_is_read)
|
||||
{
|
||||
(void) read_statistics_for_table(thd, tl->table, stat_tables);
|
||||
table_share->stats_is_read= TRUE;
|
||||
table_share->stats_cb.stats_is_read= TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2994,20 +3040,20 @@ int rename_column_in_stat_tables(THD *thd, TABLE *tab, Field *col,
|
||||
|
||||
void set_statistics_for_table(THD *thd, TABLE *table)
|
||||
{
|
||||
TABLE_STATISTICS_CB *stats_cb= &table->s->stats_cb;
|
||||
Table_statistics *read_stats= stats_cb->table_stats;
|
||||
Use_stat_tables_mode use_stat_table_mode= get_use_stat_tables_mode(thd);
|
||||
table->used_stat_records=
|
||||
(use_stat_table_mode <= COMPLEMENTARY ||
|
||||
!table->s->stats_is_read || !table->s->read_stats ||
|
||||
table->s->read_stats->cardinality_is_null) ?
|
||||
table->file->stats.records : table->s->read_stats->cardinality;
|
||||
!stats_cb->stats_is_read || read_stats->cardinality_is_null) ?
|
||||
table->file->stats.records : read_stats->cardinality;
|
||||
KEY *key_info, *key_info_end;
|
||||
for (key_info= table->key_info, key_info_end= key_info+table->s->keys;
|
||||
key_info < key_info_end; key_info++)
|
||||
{
|
||||
key_info->is_statistics_from_stat_tables=
|
||||
(use_stat_table_mode > COMPLEMENTARY &&
|
||||
table->s->stats_is_read &&
|
||||
key_info->read_stats &&
|
||||
stats_cb->stats_is_read &&
|
||||
key_info->read_stats->avg_frequency_is_inited() &&
|
||||
key_info->read_stats->get_avg_frequency(0) > 0.5);
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class Table_statistics
|
||||
public:
|
||||
my_bool cardinality_is_null; /* TRUE if the cardinality is unknown */
|
||||
ha_rows cardinality; /* Number of rows in the table */
|
||||
uchar *min_max_record_buffers; /* Record buffers for min/max values */
|
||||
Column_statistics *column_stats; /* Array of statistical data for columns */
|
||||
Index_statistics *index_stats; /* Array of statistical data for indexes */
|
||||
ulong *idx_avg_frequency; /* Array of records per key for index prefixes */
|
||||
|
10
sql/table.cc
10
sql/table.cc
@ -340,6 +340,8 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
|
||||
share->free_tables.empty();
|
||||
share->m_flush_tickets.empty();
|
||||
|
||||
init_sql_alloc(&share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
|
||||
|
||||
memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
|
||||
mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
|
||||
&share->LOCK_ha_data, MY_MUTEX_INIT_FAST);
|
||||
@ -420,6 +422,14 @@ void TABLE_SHARE::destroy()
|
||||
uint idx;
|
||||
KEY *info_it;
|
||||
|
||||
if (tmp_table == NO_TMP_TABLE)
|
||||
mysql_mutex_lock(&LOCK_ha_data);
|
||||
free_root(&stats_cb.mem_root, MYF(0));
|
||||
stats_cb.stats_can_be_read= FALSE;
|
||||
stats_cb.stats_is_read= FALSE;
|
||||
if (tmp_table == NO_TMP_TABLE)
|
||||
mysql_mutex_unlock(&LOCK_ha_data);
|
||||
|
||||
/* The mutex is initialized only for shares that are part of the TDC */
|
||||
if (tmp_table == NO_TMP_TABLE)
|
||||
mysql_mutex_destroy(&LOCK_ha_data);
|
||||
|
24
sql/table.h
24
sql/table.h
@ -547,6 +547,21 @@ typedef I_P_List <Wait_for_flush,
|
||||
Wait_for_flush_list;
|
||||
|
||||
|
||||
/**
|
||||
Control block to access table statistics loaded
|
||||
from persistent statistical tables
|
||||
*/
|
||||
|
||||
struct TABLE_STATISTICS_CB
|
||||
{
|
||||
MEM_ROOT mem_root; /* MEM_ROOT to allocate statistical data for the table */
|
||||
Table_statistics *table_stats; /* Structure to access the statistical data */
|
||||
bool stats_can_be_read; /* Memory for statistical data is allocated */
|
||||
bool stats_is_read; /* Statistical data for table has been read
|
||||
from statistical tables */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
This structure is shared between different table objects. There is one
|
||||
instance of table share per one table in the database.
|
||||
@ -585,14 +600,7 @@ struct TABLE_SHARE
|
||||
KEY *key_info; /* data of keys in database */
|
||||
uint *blob_field; /* Index to blobs in Field arrray*/
|
||||
|
||||
bool stats_can_be_read; /* Memory for statistical data is allocated */
|
||||
bool stats_is_read; /* Statistical data for table has been read
|
||||
from statistical tables */
|
||||
/*
|
||||
This structure is used for statistical data on the table
|
||||
that has been read from the statistical table table_stat
|
||||
*/
|
||||
Table_statistics *read_stats;
|
||||
TABLE_STATISTICS_CB stats_cb;
|
||||
|
||||
uchar *default_values; /* row with default values */
|
||||
LEX_STRING comment; /* Comment about table */
|
||||
|
Loading…
x
Reference in New Issue
Block a user