Commit 90b3eefb 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 38b21ee0
......@@ -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);
......
/*****************************************************************************
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";
}
......
/*****************************************************************************
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
......
/*****************************************************************************
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
......
/*****************************************************************************
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);
......
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