diff options
author | Igor Babaev <igor@askmonty.org> | 2013-01-08 19:34:33 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2013-01-08 19:34:33 -0800 |
commit | f853333e09b222f6d6d76d9343b6202b4769ffab (patch) | |
tree | ccbd97f5dbba13aa19469b61108bdc6e10c3a255 /sql/sql_statistics.cc | |
parent | 88b59efef6ae869bac9d14cefe2982a1061d3c93 (diff) | |
parent | 7d9df8075e4c9392f4352e6ccd86921994f264bc (diff) | |
download | mariadb-git-f853333e09b222f6d6d76d9343b6202b4769ffab.tar.gz |
Merge 5.5-mwl248 -> 10.0-base
Diffstat (limited to 'sql/sql_statistics.cc')
-rw-r--r-- | sql/sql_statistics.cc | 340 |
1 files changed, 193 insertions, 147 deletions
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index e1d2313f433..618fd9b7799 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -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,13 +1699,55 @@ 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 (!table_stats) + if (!statistics_for_command_is_needed(thd)) 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; - - 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); - 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; + 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) + { + 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; + } + + uint fields= table_share->fields; + Column_statistics *column_stats= table_stats->column_stats; + if (!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); } @@ -2380,6 +2439,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, @@ -2400,7 +2460,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++) @@ -2427,8 +2487,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) { @@ -2466,26 +2525,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. @@ -2497,7 +2541,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; } } @@ -2508,8 +2554,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; } } @@ -2564,11 +2610,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; } } } @@ -2983,20 +3029,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); } |