Commit 57059380 authored by Vasil Dimov's avatar Vasil Dimov

Fix Bug#16400412 UNNECESSARY DICT_UPDATE_STATISTICS DURING CONCURRENT

UPDATES

After checking that the table has changed too much in
row_update_statistics_if_needed() and calling dict_update_statistics(),
also check if the same condition holds after acquiring the table stats
latch. This is to avoid multiple threads concurrently entering and
executing the stats update code.

Approved by:	Marko (rb:2186)
parent f865697b
...@@ -770,8 +770,10 @@ dict_table_get( ...@@ -770,8 +770,10 @@ dict_table_get(
/* If table->ibd_file_missing == TRUE, this will /* If table->ibd_file_missing == TRUE, this will
print an error message and return without doing print an error message and return without doing
anything. */ anything. */
dict_update_statistics(table, TRUE /* only update stats dict_update_statistics(
if they have not been initialized */); table,
TRUE, /* only update stats if not initialized */
FALSE /* update even if not changed too much */);
} }
return(table); return(table);
...@@ -4340,10 +4342,14 @@ void ...@@ -4340,10 +4342,14 @@ void
dict_update_statistics( dict_update_statistics(
/*===================*/ /*===================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool only_calc_if_missing_stats)/*!< in: only ibool only_calc_if_missing_stats,/*!< in: only
update/recalc the stats if they have update/recalc the stats if they have
not been initialized yet, otherwise not been initialized yet, otherwise
do nothing */ do nothing */
ibool only_calc_if_changed_too_much)/*!< in: only
update/recalc the stats if the table
has been changed too much since the
last stats update/recalc */
{ {
dict_index_t* index; dict_index_t* index;
ulint sum_of_index_sizes = 0; ulint sum_of_index_sizes = 0;
...@@ -4373,7 +4379,10 @@ dict_update_statistics( ...@@ -4373,7 +4379,10 @@ dict_update_statistics(
dict_table_stats_lock(table, RW_X_LATCH); dict_table_stats_lock(table, RW_X_LATCH);
if (only_calc_if_missing_stats && table->stat_initialized) { if ((only_calc_if_missing_stats && table->stat_initialized)
|| (only_calc_if_changed_too_much
&& !DICT_TABLE_CHANGED_TOO_MUCH(table))) {
dict_table_stats_unlock(table, RW_X_LATCH); dict_table_stats_unlock(table, RW_X_LATCH);
return; return;
} }
...@@ -4532,7 +4541,10 @@ dict_table_print_low( ...@@ -4532,7 +4541,10 @@ dict_table_print_low(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
dict_update_statistics(table, FALSE /* update even if initialized */); dict_update_statistics(
table,
FALSE, /* update even if initialized */
FALSE /* update even if not changed too much */);
dict_table_stats_lock(table, RW_S_LATCH); dict_table_stats_lock(table, RW_S_LATCH);
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 2013, Innobase Oy. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under 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 the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -352,8 +352,10 @@ dict_process_sys_tables_rec( ...@@ -352,8 +352,10 @@ dict_process_sys_tables_rec(
/* Update statistics if DICT_TABLE_UPDATE_STATS /* Update statistics if DICT_TABLE_UPDATE_STATS
is set */ is set */
dict_update_statistics(*table, FALSE /* update even if dict_update_statistics(
initialized */); *table,
FALSE, /* update even if initialized */
FALSE /* update even if not changed too much */);
} }
return(NULL); return(NULL);
......
...@@ -8122,9 +8122,10 @@ ha_innobase::info_low( ...@@ -8122,9 +8122,10 @@ ha_innobase::info_low(
prebuilt->trx->op_info = "updating table statistics"; prebuilt->trx->op_info = "updating table statistics";
dict_update_statistics(ib_table, dict_update_statistics(
FALSE /* update even if stats ib_table,
are initialized */); FALSE, /* update even if initialized */
FALSE /* update even if not changed too much */);
prebuilt->trx->op_info = "returning various info to MySQL"; prebuilt->trx->op_info = "returning various info to MySQL";
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under 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 the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -1124,6 +1124,18 @@ ulint ...@@ -1124,6 +1124,18 @@ ulint
dict_index_calc_min_rec_len( dict_index_calc_min_rec_len(
/*========================*/ /*========================*/
const dict_index_t* index); /*!< in: index */ const dict_index_t* index); /*!< in: index */
/** Calculate new statistics if 1 / 16 of table has been modified
since the last time a statistics batch was run.
We calculate statistics at most every 16th round, since we may have
a counter table which is very small and updated very often.
@param t table
@return true if the table has changed too much and stats need to be
recalculated
*/
#define DICT_TABLE_CHANGED_TOO_MUCH(t) \
((ib_int64_t) (t)->stat_modified_counter > 16 + (t)->stat_n_rows / 16)
/*********************************************************************//** /*********************************************************************//**
Calculates new estimates for table and index statistics. The statistics Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */ are used in query optimization. */
...@@ -1132,10 +1144,14 @@ void ...@@ -1132,10 +1144,14 @@ void
dict_update_statistics( dict_update_statistics(
/*===================*/ /*===================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool only_calc_if_missing_stats);/*!< in: only ibool only_calc_if_missing_stats,/*!< in: only
update/recalc the stats if they have update/recalc the stats if they have
not been initialized yet, otherwise not been initialized yet, otherwise
do nothing */ do nothing */
ibool only_calc_if_changed_too_much);/*!< in: only
update/recalc the stats if the table
has been changed too much since the
last stats update/recalc */
/********************************************************************//** /********************************************************************//**
Reserves the dictionary system mutex for MySQL. */ Reserves the dictionary system mutex for MySQL. */
UNIV_INTERN UNIV_INTERN
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under 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 the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -607,7 +607,13 @@ struct dict_table_struct{ ...@@ -607,7 +607,13 @@ struct dict_table_struct{
/*!< flag: TRUE if the maximum length of /*!< flag: TRUE if the maximum length of
a single row exceeds BIG_ROW_SIZE; a single row exceeds BIG_ROW_SIZE;
initialized in dict_table_add_to_cache() */ initialized in dict_table_add_to_cache() */
/** Statistics for query optimization */ /** Statistics for query optimization.
The following stat_* members are usually
protected by dict_table_stats_lock(). In
some exceptional cases (performance critical
code paths) we access or modify stat_n_rows
and stat_modified_counter without any
protection. */
/* @{ */ /* @{ */
unsigned stat_initialized:1; /*!< TRUE if statistics have unsigned stat_initialized:1; /*!< TRUE if statistics have
been calculated the first time been calculated the first time
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2000, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under 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 the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -962,17 +962,12 @@ row_update_statistics_if_needed( ...@@ -962,17 +962,12 @@ row_update_statistics_if_needed(
table->stat_modified_counter = counter + 1; table->stat_modified_counter = counter + 1;
/* Calculate new statistics if 1 / 16 of table has been modified if (DICT_TABLE_CHANGED_TOO_MUCH(table)) {
since the last time a statistics batch was run, or if
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
We calculate statistics at most every 16th round, since we may have
a counter table which is very small and updated very often. */
if (counter > 2000000000 dict_update_statistics(
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) { table,
FALSE, /* update even if stats are initialized */
dict_update_statistics(table, FALSE /* update even if stats TRUE /* only update if stats changed too much */);
are initialized */);
} }
} }
...@@ -3050,8 +3045,10 @@ next_rec: ...@@ -3050,8 +3045,10 @@ next_rec:
dict_table_autoinc_lock(table); dict_table_autoinc_lock(table);
dict_table_autoinc_initialize(table, 1); dict_table_autoinc_initialize(table, 1);
dict_table_autoinc_unlock(table); dict_table_autoinc_unlock(table);
dict_update_statistics(table, FALSE /* update even if stats are dict_update_statistics(
initialized */); table,
FALSE, /* update even if stats are initialized */
FALSE /* update even if not changed too much */);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
......
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