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)
This commit is contained in:
parent
38b21ee0d7
commit
90b3eefb32
@ -770,8 +770,10 @@ dict_table_get(
|
||||
/* If table->ibd_file_missing == TRUE, this will
|
||||
print an error message and return without doing
|
||||
anything. */
|
||||
dict_update_statistics(table, TRUE /* only update stats
|
||||
if they have not been initialized */);
|
||||
dict_update_statistics(
|
||||
table,
|
||||
TRUE, /* only update stats if not initialized */
|
||||
FALSE /* update even if not changed too much */);
|
||||
}
|
||||
|
||||
return(table);
|
||||
@ -4340,10 +4342,14 @@ void
|
||||
dict_update_statistics(
|
||||
/*===================*/
|
||||
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
|
||||
not been initialized yet, otherwise
|
||||
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;
|
||||
ulint sum_of_index_sizes = 0;
|
||||
@ -4373,7 +4379,10 @@ dict_update_statistics(
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -4532,7 +4541,10 @@ dict_table_print_low(
|
||||
|
||||
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);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
|
||||
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
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -352,8 +352,10 @@ dict_process_sys_tables_rec(
|
||||
|
||||
/* Update statistics if DICT_TABLE_UPDATE_STATS
|
||||
is set */
|
||||
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 */);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
|
@ -8122,9 +8122,10 @@ ha_innobase::info_low(
|
||||
|
||||
prebuilt->trx->op_info = "updating table statistics";
|
||||
|
||||
dict_update_statistics(ib_table,
|
||||
FALSE /* update even if stats
|
||||
are initialized */);
|
||||
dict_update_statistics(
|
||||
ib_table,
|
||||
FALSE, /* update even if initialized */
|
||||
FALSE /* update even if not changed too much */);
|
||||
|
||||
prebuilt->trx->op_info = "returning various info to MySQL";
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
|
||||
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
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -1124,6 +1124,18 @@ ulint
|
||||
dict_index_calc_min_rec_len(
|
||||
/*========================*/
|
||||
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
|
||||
are used in query optimization. */
|
||||
@ -1132,10 +1144,14 @@ void
|
||||
dict_update_statistics(
|
||||
/*===================*/
|
||||
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
|
||||
not been initialized yet, otherwise
|
||||
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. */
|
||||
UNIV_INTERN
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
|
||||
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
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -607,7 +607,13 @@ struct dict_table_struct{
|
||||
/*!< flag: TRUE if the maximum length of
|
||||
a single row exceeds BIG_ROW_SIZE;
|
||||
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
|
||||
been calculated the first time
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
|
||||
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
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -962,17 +962,12 @@ row_update_statistics_if_needed(
|
||||
|
||||
table->stat_modified_counter = counter + 1;
|
||||
|
||||
/* Calculate new statistics if 1 / 16 of table has been modified
|
||||
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 (DICT_TABLE_CHANGED_TOO_MUCH(table)) {
|
||||
|
||||
if (counter > 2000000000
|
||||
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
|
||||
|
||||
dict_update_statistics(table, FALSE /* update even if stats
|
||||
are initialized */);
|
||||
dict_update_statistics(
|
||||
table,
|
||||
FALSE, /* update even if stats are initialized */
|
||||
TRUE /* only update if stats changed too much */);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3050,8 +3045,10 @@ next_rec:
|
||||
dict_table_autoinc_lock(table);
|
||||
dict_table_autoinc_initialize(table, 1);
|
||||
dict_table_autoinc_unlock(table);
|
||||
dict_update_statistics(table, FALSE /* update even if stats are
|
||||
initialized */);
|
||||
dict_update_statistics(
|
||||
table,
|
||||
FALSE, /* update even if stats are initialized */
|
||||
FALSE /* update even if not changed too much */);
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user