diff options
Diffstat (limited to 'sql/sql_statistics.cc')
-rw-r--r-- | sql/sql_statistics.cc | 306 |
1 files changed, 85 insertions, 221 deletions
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 83013b8b1e7..b65f460c896 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1,5 +1,5 @@ /* Copyright (C) 2009 MySQL AB - Copyright (c) 2019, MariaDB Corporation. + Copyright (c) 2019, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2214,27 +2214,13 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share) DBUG_ENTER("alloc_statistics_for_table_share"); - DEBUG_SYNC(thd, "statistics_mem_alloc_start1"); - DEBUG_SYNC(thd, "statistics_mem_alloc_start2"); - - mysql_mutex_lock(&table_share->LOCK_share); - - if (stats_cb->stats_can_be_read) - { - mysql_mutex_unlock(&table_share->LOCK_share); - 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) - { - mysql_mutex_unlock(&table_share->LOCK_share); DBUG_RETURN(1); - } memset(table_stats, 0, sizeof(Table_statistics)); stats_cb->table_stats= table_stats; } @@ -2300,89 +2286,11 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share) } } } - - if (column_stats && index_stats && idx_avg_frequency) - stats_cb->stats_can_be_read= TRUE; - - mysql_mutex_unlock(&table_share->LOCK_share); - - DBUG_RETURN(0); + DBUG_RETURN(column_stats && index_stats && idx_avg_frequency ? 0 : 1); } /** - @brief - Allocate memory for the histogram used by a table share - - @param - thd Thread handler - @param - table_share Table share for which the memory for histogram data is allocated - @param - is_safe TRUE <-> at any time only one thread can perform the function - - @note - The function allocates the memory for the histogram built for a table in the - table's share memory with the intention to read the data there from the - system persistent statistical table mysql.column_stats, - The memory is allocated in the table_share's mem_root. - If the parameter is_safe is TRUE then it is guaranteed that at any given time - only one thread is executed the code of the function. - - @retval - 0 If the memory for all statistical data has been successfully allocated - @retval - 1 Otherwise - - @note - Currently the function always is called with the parameter is_safe set - to FALSE. -*/ - -static -int alloc_histograms_for_table_share(THD* thd, TABLE_SHARE *table_share, - bool is_safe) -{ - TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb; - - DBUG_ENTER("alloc_histograms_for_table_share"); - - if (!is_safe) - mysql_mutex_lock(&table_share->LOCK_share); - - if (stats_cb->histograms_can_be_read) - { - if (!is_safe) - mysql_mutex_unlock(&table_share->LOCK_share); - DBUG_RETURN(0); - } - - Table_statistics *table_stats= stats_cb->table_stats; - ulong total_hist_size= table_stats->total_hist_size; - - if (total_hist_size && !table_stats->histograms) - { - uchar *histograms= (uchar *) alloc_root(&stats_cb->mem_root, - total_hist_size); - if (!histograms) - { - if (!is_safe) - mysql_mutex_unlock(&table_share->LOCK_share); - DBUG_RETURN(1); - } - memset(histograms, 0, total_hist_size); - table_stats->histograms= histograms; - stats_cb->histograms_can_be_read= TRUE; - } - - if (!is_safe) - mysql_mutex_unlock(&table_share->LOCK_share); - - DBUG_RETURN(0); - -} - -/** @brief Initialize the aggregation fields to collect statistics on a column @@ -2923,15 +2831,26 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) Field **field_ptr; KEY *key_info, *key_info_end; TABLE_SHARE *table_share= table->s; - Table_statistics *read_stats= table_share->stats_cb.table_stats; enum_check_fields old_check_level= thd->count_cuted_fields; DBUG_ENTER("read_statistics_for_table"); + DEBUG_SYNC(thd, "statistics_mem_alloc_start1"); + DEBUG_SYNC(thd, "statistics_mem_alloc_start2"); + + if (!table_share->stats_cb.start_stats_load()) + DBUG_RETURN(table_share->stats_cb.stats_are_ready() ? 0 : 1); + + if (alloc_statistics_for_table_share(thd, table_share)) + { + table_share->stats_cb.abort_stats_load(); + DBUG_RETURN(1); + } /* Don't write warnings for internal field conversions */ thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* Read statistics from the statistical table table_stats */ + Table_statistics *read_stats= table_share->stats_cb.table_stats; stat_table= stat_tables[TABLE_STAT].table; Table_stat table_stat(stat_table, table); table_stat.set_key_fields(); @@ -2948,7 +2867,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) column_stat.get_stat_values(); total_hist_size+= table_field->read_stats->histogram.get_size(); } - read_stats->total_hist_size= total_hist_size; + table_share->stats_cb.total_hist_size= total_hist_size; /* Read statistics from the statistical table index_stats */ stat_table= stat_tables[INDEX_STAT].table; @@ -3010,9 +2929,8 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) } } - table->stats_is_read= TRUE; thd->count_cuted_fields= old_check_level; - + table_share->stats_cb.end_stats_load(); DBUG_RETURN(0); } @@ -3052,71 +2970,6 @@ void delete_stat_values_for_table_share(TABLE_SHARE *table_share) /** @brief - Check whether any statistics is to be read for tables from a table list - - @param - thd The thread handle - @param - tables The tables list for whose tables the check is to be done - - @details - The function checks whether for any of the tables opened and locked for - a statement statistics from statistical tables is needed to be read. - - @retval - TRUE statistics for any of the tables is needed to be read - @retval - FALSE Otherwise -*/ - -static -bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables) -{ - if (!tables) - return FALSE; - - /* - Do not read statistics for any query that explicity involves - statistical tables, failure to to do so we may end up - in a deadlock. - */ - - for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) - { - if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table) - { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && - table_share->table_category != TABLE_CATEGORY_USER - && is_stat_table(&tl->db, &tl->alias)) - return FALSE; - } - } - - for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) - { - if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table) - { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && - table_share->stats_cb.stats_can_be_read && - (!table_share->stats_cb.stats_is_read || - (!table_share->stats_cb.histograms_are_read && - thd->variables.optimizer_use_condition_selectivity > 3))) - return TRUE; - if (table_share->stats_cb.stats_is_read) - tl->table->stats_is_read= TRUE; - if (table_share->stats_cb.histograms_are_read) - tl->table->histograms_are_read= TRUE; - } - } - - return FALSE; -} - - -/** - @brief Read histogram for a table from the persistent statistical tables @param @@ -3150,26 +3003,25 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables) static int read_histograms_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) { - TABLE_SHARE *table_share= table->s; - + TABLE_STATISTICS_CB *stats_cb= &table->s->stats_cb; DBUG_ENTER("read_histograms_for_table"); - if (!table_share->stats_cb.histograms_can_be_read) + if (stats_cb->start_histograms_load()) { - (void) alloc_histograms_for_table_share(thd, table_share, FALSE); - } - if (table_share->stats_cb.histograms_can_be_read && - !table_share->stats_cb.histograms_are_read) - { - Field **field_ptr; - uchar *histogram= table_share->stats_cb.table_stats->histograms; - TABLE *stat_table= stat_tables[COLUMN_STAT].table; - Column_stat column_stat(stat_table, table); - for (field_ptr= table_share->field; *field_ptr; field_ptr++) + uchar *histogram= (uchar *) alloc_root(&stats_cb->mem_root, + stats_cb->total_hist_size); + if (!histogram) + { + stats_cb->abort_histograms_load(); + DBUG_RETURN(1); + } + memset(histogram, 0, stats_cb->total_hist_size); + + Column_stat column_stat(stat_tables[COLUMN_STAT].table, table); + for (Field **field_ptr= table->s->field; *field_ptr; field_ptr++) { Field *table_field= *field_ptr; - uint hist_size= table_field->read_stats->histogram.get_size(); - if (hist_size) + if (uint hist_size= table_field->read_stats->histogram.get_size()) { column_stat.set_key_fields(table_field); table_field->read_stats->histogram.set_values(histogram); @@ -3177,8 +3029,9 @@ int read_histograms_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) histogram+= hist_size; } } + stats_cb->end_histograms_load(); } - + table->histograms_are_read= true; DBUG_RETURN(0); } @@ -3226,6 +3079,23 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables) } +static void dump_stats_from_share_to_table(TABLE *table) +{ + TABLE_SHARE *table_share= table->s; + KEY *key_info= table_share->key_info; + KEY *key_info_end= key_info + table_share->keys; + KEY *table_key_info= 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= table->field; + for ( ; *field_ptr; field_ptr++, table_field_ptr++) + (*table_field_ptr)->read_stats= (*field_ptr)->read_stats; + table->stats_is_read= true; +} + + int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) { TABLE_LIST stat_tables[STATISTICS_TABLES]; @@ -3236,38 +3106,42 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) if (thd->bootstrap || thd->variables.use_stat_tables == NEVER) DBUG_RETURN(0); + bool found_stat_table= false; + bool statistics_for_tables_is_needed= false; + for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) { - if (tl->table) + TABLE_SHARE *table_share; + if (!tl->is_view_or_derived() && tl->table && (table_share= tl->table->s) && + table_share->tmp_table == NO_TMP_TABLE) { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && table_share->table_category == TABLE_CATEGORY_USER && - table_share->tmp_table == NO_TMP_TABLE) + if (table_share->table_category == TABLE_CATEGORY_USER) { - if (table_share->stats_cb.stats_can_be_read || - !alloc_statistics_for_table_share(thd, table_share)) + if (table_share->stats_cb.stats_are_ready()) { - 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= tl->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= tl->table->field; - for ( ; *field_ptr; field_ptr++, table_field_ptr++) - (*table_field_ptr)->read_stats= (*field_ptr)->read_stats; - tl->table->stats_is_read= table_share->stats_cb.stats_is_read; - } + if (!tl->table->stats_is_read) + dump_stats_from_share_to_table(tl->table); + tl->table->histograms_are_read= + table_share->stats_cb.histograms_are_ready(); + if (table_share->stats_cb.histograms_are_ready() || + thd->variables.optimizer_use_condition_selectivity <= 3) + continue; } + statistics_for_tables_is_needed= true; } + else if (is_stat_table(&tl->db, &tl->alias)) + found_stat_table= true; } } DEBUG_SYNC(thd, "statistics_read_start"); - if (!statistics_for_tables_is_needed(thd, tables)) + /* + Do not read statistics for any query that explicity involves + statistical tables, failure to to do so we may end up + in a deadlock. + */ + if (found_stat_table || !statistics_for_tables_is_needed) DBUG_RETURN(0); if (open_stat_tables(thd, stat_tables, &open_tables_backup, FALSE)) @@ -3275,32 +3149,22 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) { - if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table) - { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && !(table_share->table_category == TABLE_CATEGORY_USER)) - continue; - - if (table_share && - table_share->stats_cb.stats_can_be_read && - !table_share->stats_cb.stats_is_read) + TABLE_SHARE *table_share; + if (!tl->is_view_or_derived() && tl->table && (table_share= tl->table->s) && + table_share->tmp_table == NO_TMP_TABLE && + table_share->table_category == TABLE_CATEGORY_USER) + { + if (!tl->table->stats_is_read) { - (void) read_statistics_for_table(thd, tl->table, stat_tables); - table_share->stats_cb.stats_is_read= TRUE; + if (!read_statistics_for_table(thd, tl->table, stat_tables)) + dump_stats_from_share_to_table(tl->table); + else + continue; } - if (table_share->stats_cb.stats_is_read) - tl->table->stats_is_read= TRUE; - if (thd->variables.optimizer_use_condition_selectivity > 3 && - table_share && table_share->stats_cb.stats_can_be_read && - !table_share->stats_cb.histograms_are_read) - { + if (thd->variables.optimizer_use_condition_selectivity > 3) (void) read_histograms_for_table(thd, tl->table, stat_tables); - table_share->stats_cb.histograms_are_read= TRUE; - } - if (table_share->stats_cb.histograms_are_read) - tl->table->histograms_are_read= TRUE; } - } + } close_system_tables(thd, &open_tables_backup); |