summaryrefslogtreecommitdiff
path: root/sql/sql_statistics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_statistics.cc')
-rw-r--r--sql/sql_statistics.cc306
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);