diff options
author | Vasil Dimov <vasil.dimov@oracle.com> | 2013-03-18 17:20:30 +0200 |
---|---|---|
committer | Vasil Dimov <vasil.dimov@oracle.com> | 2013-03-18 17:20:30 +0200 |
commit | 57059380b5b5a76bbfccf8922451c5aa8cfd49b7 (patch) | |
tree | 539cfbfc86cc6ab12af93c1faadddd5e5edddd2a /storage/innobase | |
parent | f865697b9e1b980a63b99037f451276d5a2f59ab (diff) | |
download | mariadb-git-57059380b5b5a76bbfccf8922451c5aa8cfd49b7.tar.gz |
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)
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/dict/dict0dict.c | 22 | ||||
-rw-r--r-- | storage/innobase/dict/dict0load.c | 8 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 7 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.h | 20 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 10 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.c | 23 |
6 files changed, 62 insertions, 28 deletions
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index a887ff0b1ca..215ac35ae5b 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -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); diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index b36042e7f7a..e813afea519 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -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); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 997fdb6244c..515abc6744e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -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"; } diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 54af14313c4..7b55a59ea19 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -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 diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 980417715b3..15b53a45afa 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -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 diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 77fa6518b35..d97476dcdb1 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -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); |