=== modified file 'storage/innobase/dict/dict0dict.c' --- storage/innobase/dict/dict0dict.c revid:venkatesh.duggirala@oracle.com-20130313105911-mlnwn47ft16a38qp +++ storage/innobase/dict/dict0dict.c 2013-03-14 15:05:59 +0000 @@ -767,14 +767,16 @@ dict_table_get( mutex_exit(&(dict_sys->mutex)); if (table != NULL) { /* 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); } #endif /* !UNIV_HOTBACKUP */ @@ -4337,16 +4339,20 @@ Calculates new estimates for table and i are used in query optimization. */ UNIV_INTERN 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; if (table->ibd_file_missing) { ut_print_timestamp(stderr); @@ -4370,13 +4376,16 @@ dict_update_statistics( return; } 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; } do { if (UNIV_LIKELY @@ -4529,13 +4538,16 @@ dict_table_print_low( dict_index_t* index; dict_foreign_t* foreign; ulint i; 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); fprintf(stderr, "--------------------------------------\n" "TABLE: name %s, id %llu, flags %lx, columns %lu," === modified file 'storage/innobase/dict/dict0load.c' --- storage/innobase/dict/dict0load.c revid:venkatesh.duggirala@oracle.com-20130313105911-mlnwn47ft16a38qp +++ storage/innobase/dict/dict0load.c 2013-03-14 08:08:24 +0000 @@ -349,14 +349,16 @@ dict_process_sys_tables_rec( if ((status & DICT_TABLE_UPDATE_STATS) && dict_table_get_first_index(*table)) { /* 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); } /********************************************************************//** === modified file 'storage/innobase/handler/ha_innodb.cc' --- storage/innobase/handler/ha_innodb.cc revid:venkatesh.duggirala@oracle.com-20130313105911-mlnwn47ft16a38qp +++ storage/innobase/handler/ha_innodb.cc 2013-03-14 08:08:14 +0000 @@ -8119,15 +8119,16 @@ ha_innobase::info_low( if (called_from_analyze || innobase_stats_on_metadata) { /* In sql_show we call with this flag: update then statistics so that they are up-to-date */ 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"; } my_snprintf(path, sizeof(path), "%s/%s%s", mysql_data_home, ib_table->name, reg_ext); === modified file 'storage/innobase/include/dict0dict.h' --- storage/innobase/include/dict0dict.h revid:venkatesh.duggirala@oracle.com-20130313105911-mlnwn47ft16a38qp +++ storage/innobase/include/dict0dict.h 2013-03-15 14:49:20 +0000 @@ -1121,24 +1121,40 @@ dict_index_get_space_reserve(void); Calculates the minimum record length in an index. */ UNIV_INTERN 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. */ UNIV_INTERN 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 void dict_mutex_enter_for_mysql(void); /*============================*/ === modified file 'storage/innobase/include/dict0mem.h' --- storage/innobase/include/dict0mem.h revid:venkatesh.duggirala@oracle.com-20130313105911-mlnwn47ft16a38qp +++ storage/innobase/include/dict0mem.h 2013-03-15 14:54:09 +0000 @@ -604,13 +604,19 @@ struct dict_table_struct{ #endif /* UNIV_DEBUG */ /*----------------------*/ unsigned big_rows:1; /*!< 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 after database startup or table creation */ ib_int64_t stat_n_rows; /*!< approximate number of rows in the table; === modified file 'storage/innobase/row/row0mysql.c' --- storage/innobase/row/row0mysql.c revid:venkatesh.duggirala@oracle.com-20130313105911-mlnwn47ft16a38qp +++ storage/innobase/row/row0mysql.c 2013-03-14 08:15:36 +0000 @@ -959,23 +959,18 @@ row_update_statistics_if_needed( ulint counter; counter = table->stat_modified_counter; 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 the above condition holds */); } } /*********************************************************************//** Unlocks AUTO_INC type locks that were possibly reserved by a trx. This function should be called at the the end of an SQL statement, by the @@ -3047,14 +3042,16 @@ next_rec: } /* Reset auto-increment. */ 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); funct_exit: row_mysql_unlock_data_dictionary(trx);