summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorVasil Dimov <vasil.dimov@oracle.com>2013-03-18 17:20:30 +0200
committerVasil Dimov <vasil.dimov@oracle.com>2013-03-18 17:20:30 +0200
commit57059380b5b5a76bbfccf8922451c5aa8cfd49b7 (patch)
tree539cfbfc86cc6ab12af93c1faadddd5e5edddd2a /storage/innobase
parentf865697b9e1b980a63b99037f451276d5a2f59ab (diff)
downloadmariadb-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.c22
-rw-r--r--storage/innobase/dict/dict0load.c8
-rw-r--r--storage/innobase/handler/ha_innodb.cc7
-rw-r--r--storage/innobase/include/dict0dict.h20
-rw-r--r--storage/innobase/include/dict0mem.h10
-rw-r--r--storage/innobase/row/row0mysql.c23
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);