mirror of
https://github.com/MariaDB/server.git
synced 2025-04-18 21:44:20 +03:00
MDEV-35000: dict_table_close() breaks STATS_AUTO_RECALC
stats_deinit(): Replaces dict_stats_deinit(). Deinitialize the statistics for persistent tables, so that they will be reloaded or recalculated on a subsequent ha_innobase::open(). ha_innobase::rename_table(): Invoke stats_deinit() so that the subsequent ha_innobase::open() will reload the InnoDB persistent statistics. That is, it will remain possible to have the InnoDB persistent statistics reloaded by executing the following: RENAME TABLE t TO tmp, tmp TO t; dict_table_close(table): Replaced with table->release(). There will no longer be any logic that would attempt to ensure that the InnoDB persistent statistics will be reloaded after FLUSH TABLES has been executed. This also fixes the problem that dict_table_t::stat_modified_counter would be frequently reset to 0, whenever ha_innobase::open() is invoked after the table reference count had dropped to 0. dict_table_close(table, thd, mdl): Remove the parameter "dict_locked". Do not try to invalidate the statistics. ha_innobase::statistics_init(): Replaces dict_stats_init(table). Reviewed by: Thirunarayanan Balathandayuthapani
This commit is contained in:
parent
1ed09cfdcb
commit
6e6a1b316c
@ -46,23 +46,70 @@ ALTER TABLE t1 MODIFY a DECIMAL(10,0);
|
||||
SELECT * FROM t1,t2 WHERE a=d;
|
||||
a b c pk d e
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'd'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'd'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'f'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'f'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'g'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'k'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'm'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'm'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'm'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'o'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'q'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'r'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'u'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'w'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'x'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'x'
|
||||
Warning 1292 Truncated incorrect DECIMAL value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'w'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'w'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'w'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
ALTER TABLE t1 MODIFY a DOUBLE;
|
||||
SELECT * FROM t1,t2 WHERE a=d;
|
||||
a b c pk d e
|
||||
@ -84,6 +131,53 @@ Warning 1292 Truncated incorrect DOUBLE value: 'w'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'w'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'w'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'x'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'y'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'd'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'f'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'g'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'k'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'm'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'o'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'q'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'r'
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'u'
|
||||
DROP TABLE t1,t2;
|
||||
#
|
||||
# End of 10.2 tests
|
||||
|
@ -38,6 +38,10 @@ idxa n_diff_pfx01 a
|
||||
idxa n_diff_pfx02 a,DB_ROW_ID
|
||||
idxa n_leaf_pages Number of leaf pages in the index
|
||||
idxa size Number of pages in the index
|
||||
idxb n_diff_pfx01 b
|
||||
idxb n_diff_pfx02 b,DB_ROW_ID
|
||||
idxb n_leaf_pages Number of leaf pages in the index
|
||||
idxb size Number of pages in the index
|
||||
vidxcd n_diff_pfx01 c
|
||||
vidxcd n_diff_pfx02 c,d
|
||||
vidxcd n_diff_pfx03 c,d,DB_ROW_ID
|
||||
@ -54,6 +58,14 @@ index_name stat_name stat_description
|
||||
GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID
|
||||
GEN_CLUST_INDEX n_leaf_pages Number of leaf pages in the index
|
||||
GEN_CLUST_INDEX size Number of pages in the index
|
||||
idxb n_diff_pfx01 b
|
||||
idxb n_diff_pfx02 b,DB_ROW_ID
|
||||
idxb n_leaf_pages Number of leaf pages in the index
|
||||
idxb size Number of pages in the index
|
||||
vidxcd n_diff_pfx01 d
|
||||
vidxcd n_diff_pfx02 d,DB_ROW_ID
|
||||
vidxcd n_leaf_pages Number of leaf pages in the index
|
||||
vidxcd size Number of pages in the index
|
||||
ALTER TABLE t ADD INDEX vidxe (e), ALGORITHM=INPLACE;
|
||||
select count(*) from t;
|
||||
count(*)
|
||||
@ -65,6 +77,18 @@ index_name stat_name stat_description
|
||||
GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID
|
||||
GEN_CLUST_INDEX n_leaf_pages Number of leaf pages in the index
|
||||
GEN_CLUST_INDEX size Number of pages in the index
|
||||
idxb n_diff_pfx01 b
|
||||
idxb n_diff_pfx02 b,DB_ROW_ID
|
||||
idxb n_leaf_pages Number of leaf pages in the index
|
||||
idxb size Number of pages in the index
|
||||
vidxcd n_diff_pfx01 d
|
||||
vidxcd n_diff_pfx02 d,DB_ROW_ID
|
||||
vidxcd n_leaf_pages Number of leaf pages in the index
|
||||
vidxcd size Number of pages in the index
|
||||
vidxe n_diff_pfx01 e
|
||||
vidxe n_diff_pfx02 e,DB_ROW_ID
|
||||
vidxe n_leaf_pages Number of leaf pages in the index
|
||||
vidxe size Number of pages in the index
|
||||
ALTER TABLE t ADD COLUMN f INT GENERATED ALWAYS AS(a + a), ADD INDEX vidxf (f), ALGORITHM=INPLACE;
|
||||
select count(*) from t;
|
||||
count(*)
|
||||
@ -76,6 +100,22 @@ index_name stat_name stat_description
|
||||
GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID
|
||||
GEN_CLUST_INDEX n_leaf_pages Number of leaf pages in the index
|
||||
GEN_CLUST_INDEX size Number of pages in the index
|
||||
idxb n_diff_pfx01 b
|
||||
idxb n_diff_pfx02 b,DB_ROW_ID
|
||||
idxb n_leaf_pages Number of leaf pages in the index
|
||||
idxb size Number of pages in the index
|
||||
vidxcd n_diff_pfx01 d
|
||||
vidxcd n_diff_pfx02 d,DB_ROW_ID
|
||||
vidxcd n_leaf_pages Number of leaf pages in the index
|
||||
vidxcd size Number of pages in the index
|
||||
vidxe n_diff_pfx01 e
|
||||
vidxe n_diff_pfx02 e,DB_ROW_ID
|
||||
vidxe n_leaf_pages Number of leaf pages in the index
|
||||
vidxe size Number of pages in the index
|
||||
vidxf n_diff_pfx01 f
|
||||
vidxf n_diff_pfx02 f,DB_ROW_ID
|
||||
vidxf n_leaf_pages Number of leaf pages in the index
|
||||
vidxf size Number of pages in the index
|
||||
ALTER TABLE t DROP INDEX vidxcd;
|
||||
SELECT index_name, stat_name, stat_description
|
||||
FROM mysql.innodb_index_stats
|
||||
@ -84,4 +124,16 @@ index_name stat_name stat_description
|
||||
GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID
|
||||
GEN_CLUST_INDEX n_leaf_pages Number of leaf pages in the index
|
||||
GEN_CLUST_INDEX size Number of pages in the index
|
||||
idxb n_diff_pfx01 b
|
||||
idxb n_diff_pfx02 b,DB_ROW_ID
|
||||
idxb n_leaf_pages Number of leaf pages in the index
|
||||
idxb size Number of pages in the index
|
||||
vidxe n_diff_pfx01 e
|
||||
vidxe n_diff_pfx02 e,DB_ROW_ID
|
||||
vidxe n_leaf_pages Number of leaf pages in the index
|
||||
vidxe size Number of pages in the index
|
||||
vidxf n_diff_pfx01 f
|
||||
vidxf n_diff_pfx02 f,DB_ROW_ID
|
||||
vidxf n_leaf_pages Number of leaf pages in the index
|
||||
vidxf size Number of pages in the index
|
||||
DROP TABLE t;
|
||||
|
@ -5,13 +5,13 @@ COUNT(*) 1
|
||||
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
COUNT(*) 3
|
||||
SELECT * FROM t;
|
||||
FLUSH TABLE t;
|
||||
DELETE FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
RENAME TABLE t TO tmp, tmp TO t;
|
||||
SELECT * FROM t;
|
||||
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
COUNT(*) 1
|
||||
@ -25,13 +25,13 @@ COUNT(*) 1
|
||||
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
COUNT(*) 3
|
||||
SELECT * FROM t;
|
||||
FLUSH TABLE t;
|
||||
DELETE FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
RENAME TABLE t TO tmp, tmp TO t;
|
||||
SELECT * FROM t;
|
||||
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
COUNT(*) 1
|
||||
@ -45,13 +45,13 @@ COUNT(*) 1
|
||||
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
COUNT(*) 3
|
||||
SELECT * FROM t;
|
||||
FLUSH TABLE t;
|
||||
DELETE FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
SELECT COUNT(*) FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
RENAME TABLE t TO tmp, tmp TO t;
|
||||
SELECT * FROM t;
|
||||
SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
COUNT(*) 0
|
||||
|
@ -125,7 +125,7 @@ WHERE
|
||||
table_name = 'test_ps_fetch' AND
|
||||
index_name = 'idx' AND
|
||||
stat_name = 'n_diff_pfx02';
|
||||
FLUSH TABLE test_ps_fetch;
|
||||
RENAME TABLE test_ps_fetch TO tmp, tmp TO test_ps_fetch;
|
||||
SELECT seq_in_index, column_name, cardinality
|
||||
FROM information_schema.statistics WHERE table_name = 'test_ps_fetch'
|
||||
ORDER BY index_name, seq_in_index;
|
||||
|
@ -17,9 +17,7 @@ CREATE TABLE t (a INT, PRIMARY KEY (a)) ENGINE=INNODB;
|
||||
-- eval $check_stats1
|
||||
-- eval $check_stats2
|
||||
|
||||
# open and close the table
|
||||
SELECT * FROM t;
|
||||
FLUSH TABLE t;
|
||||
|
||||
DELETE FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
@ -27,7 +25,8 @@ DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
-- eval $check_stats1
|
||||
-- eval $check_stats2
|
||||
|
||||
# open the table, causing stats recalc/save
|
||||
# rename and open the table, causing stats recalc/save
|
||||
RENAME TABLE t TO tmp, tmp TO t;
|
||||
SELECT * FROM t;
|
||||
|
||||
-- eval $check_stats1
|
||||
@ -43,9 +42,7 @@ CREATE TABLE t (a INT, PRIMARY KEY (a)) ENGINE=INNODB STATS_AUTO_RECALC=1;
|
||||
-- eval $check_stats1
|
||||
-- eval $check_stats2
|
||||
|
||||
# open and close the table
|
||||
SELECT * FROM t;
|
||||
FLUSH TABLE t;
|
||||
|
||||
DELETE FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
@ -53,7 +50,7 @@ DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
-- eval $check_stats1
|
||||
-- eval $check_stats2
|
||||
|
||||
# open the table, causing stats recalc/save
|
||||
RENAME TABLE t TO tmp, tmp TO t;
|
||||
SELECT * FROM t;
|
||||
|
||||
-- eval $check_stats1
|
||||
@ -69,9 +66,7 @@ CREATE TABLE t (a INT, PRIMARY KEY (a)) ENGINE=INNODB STATS_AUTO_RECALC=0;
|
||||
-- eval $check_stats1
|
||||
-- eval $check_stats2
|
||||
|
||||
# open and close the table
|
||||
SELECT * FROM t;
|
||||
FLUSH TABLE t;
|
||||
|
||||
DELETE FROM mysql.innodb_index_stats WHERE table_name = 't';
|
||||
DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
@ -79,7 +74,8 @@ DELETE FROM mysql.innodb_table_stats WHERE table_name = 't';
|
||||
-- eval $check_stats1
|
||||
-- eval $check_stats2
|
||||
|
||||
# open the table, stats should not be present, since autorecalc is disabled
|
||||
# rename the table, stats should not be present, since autorecalc is disabled
|
||||
RENAME TABLE t TO tmp, tmp TO t;
|
||||
SELECT * FROM t;
|
||||
|
||||
-- eval $check_stats1
|
||||
|
@ -69,7 +69,7 @@ table_name = 'test_ps_fetch' AND
|
||||
index_name = 'idx' AND
|
||||
stat_name = 'n_diff_pfx02';
|
||||
|
||||
FLUSH TABLE test_ps_fetch;
|
||||
RENAME TABLE test_ps_fetch TO tmp, tmp TO test_ps_fetch;
|
||||
|
||||
SELECT seq_in_index, column_name, cardinality
|
||||
FROM information_schema.statistics WHERE table_name = 'test_ps_fetch'
|
||||
|
@ -226,7 +226,6 @@ SET(INNOBASE_SOURCES
|
||||
include/dict0pagecompress.h
|
||||
include/dict0pagecompress.inl
|
||||
include/dict0stats.h
|
||||
include/dict0stats.inl
|
||||
include/dict0stats_bg.h
|
||||
include/dict0types.h
|
||||
include/dyn0buf.h
|
||||
|
@ -196,7 +196,7 @@ static void dict_stats_process_entry_from_defrag_pool(THD *thd)
|
||||
? dict_table_find_index_on_id(table, index_id) : nullptr)
|
||||
if (index->is_btree())
|
||||
dict_stats_save_defrag_stats(index);
|
||||
dict_table_close(table, false, thd, mdl);
|
||||
dict_table_close(table, thd, mdl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ dberr_t dict_stats_save_defrag_summary(dict_index_t *index, THD *thd)
|
||||
{
|
||||
release_and_exit:
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, false, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ release_and_exit:
|
||||
goto release_and_exit;
|
||||
if (strcmp(index_stats->name.m_name, INDEX_STATS_NAME))
|
||||
{
|
||||
dict_table_close(index_stats, false, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
goto release_and_exit;
|
||||
}
|
||||
|
||||
@ -272,9 +272,9 @@ release_and_exit:
|
||||
trx->rollback();
|
||||
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
trx->free();
|
||||
@ -367,7 +367,7 @@ dict_stats_save_defrag_stats(
|
||||
{
|
||||
release_and_exit:
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, false, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
|
||||
@ -384,7 +384,7 @@ release_and_exit:
|
||||
|
||||
if (strcmp(index_stats->name.m_name, INDEX_STATS_NAME))
|
||||
{
|
||||
dict_table_close(index_stats, false, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
goto release_and_exit;
|
||||
}
|
||||
|
||||
@ -424,9 +424,9 @@ release_and_exit:
|
||||
trx->rollback();
|
||||
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
trx->free();
|
||||
|
||||
|
@ -195,70 +195,6 @@ dict_tables_have_same_db(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/** Decrement the count of open handles */
|
||||
void dict_table_close(dict_table_t *table)
|
||||
{
|
||||
if (table->get_ref_count() == 1 && table->stats_is_persistent() &&
|
||||
strchr(table->name.m_name, '/'))
|
||||
{
|
||||
/* It looks like we are closing the last handle. The user could
|
||||
have executed FLUSH TABLES in order to have the statistics reloaded
|
||||
from the InnoDB persistent statistics tables. We must acquire
|
||||
exclusive dict_sys.latch to prevent a race condition with another
|
||||
thread concurrently acquiring a handle on the table. */
|
||||
dict_sys.lock(SRW_LOCK_CALL);
|
||||
if (table->release())
|
||||
{
|
||||
table->stats_mutex_lock();
|
||||
if (table->get_ref_count() == 0)
|
||||
dict_stats_deinit(table);
|
||||
table->stats_mutex_unlock();
|
||||
}
|
||||
dict_sys.unlock();
|
||||
}
|
||||
else
|
||||
table->release();
|
||||
}
|
||||
|
||||
/** Decrements the count of open handles of a table.
|
||||
@param[in,out] table table
|
||||
@param[in] dict_locked whether dict_sys.latch is being held
|
||||
@param[in] thd thread to release MDL
|
||||
@param[in] mdl metadata lock or NULL if the thread
|
||||
is a foreground one. */
|
||||
void
|
||||
dict_table_close(
|
||||
dict_table_t* table,
|
||||
bool dict_locked,
|
||||
THD* thd,
|
||||
MDL_ticket* mdl)
|
||||
{
|
||||
if (!dict_locked)
|
||||
dict_table_close(table);
|
||||
else
|
||||
{
|
||||
if (table->release() && table->stats_is_persistent() &&
|
||||
strchr(table->name.m_name, '/'))
|
||||
{
|
||||
/* Force persistent stats re-read upon next open of the table so
|
||||
that FLUSH TABLE can be used to forcibly fetch stats from disk if
|
||||
they have been manually modified. */
|
||||
table->stats_mutex_lock();
|
||||
if (table->get_ref_count() == 0)
|
||||
dict_stats_deinit(table);
|
||||
table->stats_mutex_unlock();
|
||||
}
|
||||
|
||||
ut_ad(dict_lru_validate());
|
||||
ut_ad(dict_sys.find(table));
|
||||
}
|
||||
|
||||
if (!thd || !mdl);
|
||||
else if (MDL_context *mdl_context= static_cast<MDL_context*>
|
||||
(thd_mdl_context(thd)))
|
||||
mdl_context->release_lock(mdl);
|
||||
}
|
||||
|
||||
/** Check if the table has a given (non_virtual) column.
|
||||
@param[in] table table object
|
||||
@param[in] col_name column name
|
||||
@ -585,6 +521,14 @@ dict_index_get_nth_field_pos(
|
||||
return(ULINT_UNDEFINED);
|
||||
}
|
||||
|
||||
void mdl_release(THD *thd, MDL_ticket *mdl) noexcept
|
||||
{
|
||||
if (!thd || !mdl);
|
||||
else if (MDL_context *mdl_context= static_cast<MDL_context*>
|
||||
(thd_mdl_context(thd)))
|
||||
mdl_context->release_lock(mdl);
|
||||
}
|
||||
|
||||
/** Parse the table file name into table name and database name.
|
||||
@tparam dict_frozen whether the caller holds dict_sys.latch
|
||||
@param[in,out] db_name database name buffer
|
||||
|
@ -359,7 +359,7 @@ dict_table_schema_check(
|
||||
|
||||
if (!table) {
|
||||
if (opt_bootstrap)
|
||||
return DB_TABLE_NOT_FOUND;
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
if (req_schema == &table_stats_schema) {
|
||||
if (innodb_table_stats_not_found_reported) {
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
@ -377,10 +377,10 @@ dict_table_schema_check(
|
||||
|
||||
snprintf(errstr, errstr_sz, "Table %s not found.",
|
||||
req_schema->table_name_sql);
|
||||
return DB_TABLE_NOT_FOUND;
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
|
||||
if (!table->is_readable() && !table->space) {
|
||||
if (!table->is_readable() || !table->space) {
|
||||
/* missing tablespace */
|
||||
snprintf(errstr, errstr_sz,
|
||||
"Tablespace for table %s is missing.",
|
||||
@ -491,11 +491,8 @@ dict_table_schema_check(
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks whether the persistent statistics storage exists and that all
|
||||
tables have the proper structure.
|
||||
@return true if exists and all tables are ok */
|
||||
static bool dict_stats_persistent_storage_check(bool dict_already_locked)
|
||||
dict_stats_schema_check
|
||||
dict_stats_persistent_storage_check(bool dict_already_locked) noexcept
|
||||
{
|
||||
char errstr[512];
|
||||
dberr_t ret;
|
||||
@ -521,14 +518,14 @@ static bool dict_stats_persistent_storage_check(bool dict_already_locked)
|
||||
|
||||
switch (ret) {
|
||||
case DB_SUCCESS:
|
||||
return true;
|
||||
return SCHEMA_OK;
|
||||
case DB_STATS_DO_NOT_EXIST:
|
||||
return SCHEMA_NOT_EXIST;
|
||||
default:
|
||||
if (!opt_bootstrap) {
|
||||
ib::error() << errstr;
|
||||
sql_print_error("InnoDB: %s", errstr);
|
||||
}
|
||||
/* fall through */
|
||||
case DB_STATS_DO_NOT_EXIST:
|
||||
return false;
|
||||
return SCHEMA_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,13 +541,16 @@ dberr_t dict_stats_exec_sql(pars_info_t *pinfo, const char* sql, trx_t *trx)
|
||||
{
|
||||
ut_ad(dict_sys.locked());
|
||||
|
||||
if (!dict_stats_persistent_storage_check(true))
|
||||
{
|
||||
pars_info_free(pinfo);
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
switch (dict_stats_persistent_storage_check(true)) {
|
||||
case SCHEMA_OK:
|
||||
return que_eval_sql(pinfo, sql, trx);
|
||||
case SCHEMA_INVALID:
|
||||
case SCHEMA_NOT_EXIST:
|
||||
break;
|
||||
}
|
||||
|
||||
return que_eval_sql(pinfo, sql, trx);
|
||||
pars_info_free(pinfo);
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
|
||||
|
||||
@ -1205,19 +1205,7 @@ invalid:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for table and index statistics. This function
|
||||
is relatively quick and is used to calculate transient statistics that
|
||||
are not saved on disk.
|
||||
This was the only way to calculate statistics before the
|
||||
Persistent Statistics feature was introduced.
|
||||
@return error code
|
||||
@retval DB_SUCCESS_LOCKED REC if the table under bulk insert operation */
|
||||
static
|
||||
dberr_t
|
||||
dict_stats_update_transient(
|
||||
/*========================*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
dberr_t dict_stats_update_transient(dict_table_t *table) noexcept
|
||||
{
|
||||
ut_ad(!table->stats_mutex_is_owner());
|
||||
|
||||
@ -1230,17 +1218,16 @@ dict_stats_update_transient(
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
if (!table->space) {
|
||||
/* Nothing to do. */
|
||||
empty_table:
|
||||
if (!index || !table->space) {
|
||||
dict_stats_empty_table(table, true);
|
||||
return err;
|
||||
} else if (index == NULL) {
|
||||
/* Table definition is corrupt */
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
ib::warn() << "Table " << table->name
|
||||
<< " has no indexes. Cannot calculate statistics.";
|
||||
goto empty_table;
|
||||
if (trx_id_t bulk_trx_id = table->bulk_trx_id) {
|
||||
if (trx_sys.find(nullptr, bulk_trx_id, false)) {
|
||||
dict_stats_empty_table(table, false);
|
||||
return DB_SUCCESS_LOCKED_REC;
|
||||
}
|
||||
}
|
||||
|
||||
for (; index != NULL; index = dict_table_get_next_index(index)) {
|
||||
@ -2631,17 +2618,7 @@ found_level:
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for table and index statistics. This function
|
||||
is relatively slow and is used to calculate persistent statistics that
|
||||
will be saved on disk.
|
||||
@return DB_SUCCESS or error code
|
||||
@retval DB_SUCCESS_LOCKED_REC if the table under bulk insert operation */
|
||||
static
|
||||
dberr_t
|
||||
dict_stats_update_persistent(
|
||||
/*=========================*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
dberr_t dict_stats_update_persistent(dict_table_t *table) noexcept
|
||||
{
|
||||
dict_index_t* index;
|
||||
|
||||
@ -2649,6 +2626,13 @@ dict_stats_update_persistent(
|
||||
|
||||
DEBUG_SYNC_C("dict_stats_update_persistent");
|
||||
|
||||
if (trx_id_t bulk_trx_id = table->bulk_trx_id) {
|
||||
if (trx_sys.find(nullptr, bulk_trx_id, false)) {
|
||||
dict_stats_empty_table(table, false);
|
||||
return DB_SUCCESS_LOCKED_REC;
|
||||
}
|
||||
}
|
||||
|
||||
/* analyze the clustered index first */
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
@ -2747,6 +2731,18 @@ dict_stats_update_persistent(
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
dberr_t dict_stats_update_persistent_try(dict_table_t *table)
|
||||
{
|
||||
if (table->stats_is_persistent() &&
|
||||
dict_stats_persistent_storage_check(false) == SCHEMA_OK)
|
||||
{
|
||||
if (dberr_t err= dict_stats_update_persistent(table))
|
||||
return err;
|
||||
return dict_stats_save(table);
|
||||
}
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
#include "mysql_com.h"
|
||||
/** Save an individual index's statistic into the persistent statistics
|
||||
storage.
|
||||
@ -2825,14 +2821,14 @@ dict_stats_save_index_stat(
|
||||
"END;", trx);
|
||||
|
||||
if (UNIV_UNLIKELY(ret != DB_SUCCESS)) {
|
||||
if (innodb_index_stats_not_found == false &&
|
||||
index->stats_error_printed == false) {
|
||||
if (innodb_index_stats_not_found == false
|
||||
&& !index->table->stats_error_printed) {
|
||||
index->table->stats_error_printed = true;
|
||||
ib::error() << "Cannot save index statistics for table "
|
||||
<< index->table->name
|
||||
<< ", index " << index->name
|
||||
<< ", stat name \"" << stat_name << "\": "
|
||||
<< ret;
|
||||
index->stats_error_printed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2874,17 +2870,11 @@ dict_stats_report_error(dict_table_t* table, bool defragment)
|
||||
return err;
|
||||
}
|
||||
|
||||
/** Save the table's statistics into the persistent statistics storage.
|
||||
@param[in] table table whose stats to save
|
||||
@param[in] only_for_index if this is non-NULL, then stats for indexes
|
||||
that are not equal to it will not be saved, if NULL, then all indexes' stats
|
||||
are saved
|
||||
/** Save the persistent statistics of a table or an index.
|
||||
@param table table whose stats to save
|
||||
@param only_for_index the index ID to save statistics for (0=all)
|
||||
@return DB_SUCCESS or error code */
|
||||
static
|
||||
dberr_t
|
||||
dict_stats_save(
|
||||
dict_table_t* table,
|
||||
const index_id_t* only_for_index)
|
||||
dberr_t dict_stats_save(dict_table_t* table, index_id_t index_id)
|
||||
{
|
||||
pars_info_t* pinfo;
|
||||
char db_utf8[MAX_DB_UTF8_LEN];
|
||||
@ -2921,7 +2911,7 @@ dict_stats_save(
|
||||
|| strcmp(table_stats->name.m_name, TABLE_STATS_NAME)) {
|
||||
release_and_exit:
|
||||
if (table_stats) {
|
||||
dict_table_close(table_stats, false, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
}
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
@ -2938,7 +2928,7 @@ release_and_exit:
|
||||
goto release_and_exit;
|
||||
}
|
||||
if (strcmp(index_stats->name.m_name, INDEX_STATS_NAME)) {
|
||||
dict_table_close(index_stats, false, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
goto release_and_exit;
|
||||
}
|
||||
|
||||
@ -2998,8 +2988,14 @@ release_and_exit:
|
||||
"END;", trx);
|
||||
|
||||
if (UNIV_UNLIKELY(ret != DB_SUCCESS)) {
|
||||
ib::error() << "Cannot save table statistics for table "
|
||||
<< table->name << ": " << ret;
|
||||
sql_print_error("InnoDB: Cannot save table statistics for"
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
" table %.*s.%s: %s",
|
||||
#else
|
||||
" table %`.*s.%`s: %s",
|
||||
#endif
|
||||
int(table->name.dblen()), table->name.m_name,
|
||||
table->name.basename(), ut_strerr(ret));
|
||||
rollback_and_exit:
|
||||
trx->rollback();
|
||||
free_and_exit:
|
||||
@ -3007,8 +3003,8 @@ free_and_exit:
|
||||
dict_sys.unlock();
|
||||
unlocked_free_and_exit:
|
||||
trx->free();
|
||||
dict_table_close(table_stats, false, thd, mdl_table);
|
||||
dict_table_close(index_stats, false, thd, mdl_index);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3042,7 +3038,7 @@ unlocked_free_and_exit:
|
||||
|
||||
index = it->second;
|
||||
|
||||
if (only_for_index != NULL && index->id != *only_for_index) {
|
||||
if (index_id != 0 && index->id != index_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3112,6 +3108,14 @@ unlocked_free_and_exit:
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
void dict_stats_empty_table_and_save(dict_table_t *table)
|
||||
{
|
||||
dict_stats_empty_table(table, true);
|
||||
if (table->stats_is_persistent() &&
|
||||
dict_stats_persistent_storage_check(false) == SCHEMA_OK)
|
||||
dict_stats_save(table);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Called for the row that is selected by
|
||||
SELECT ... FROM mysql.innodb_table_stats WHERE table='...'
|
||||
@ -3461,14 +3465,8 @@ dict_stats_fetch_index_stats_step(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Read table's statistics from the persistent statistics storage.
|
||||
@return DB_SUCCESS or error code */
|
||||
static
|
||||
dberr_t
|
||||
dict_stats_fetch_from_ps(
|
||||
/*=====================*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
/** Read the stored persistent statistics of a table. */
|
||||
dberr_t dict_stats_fetch_from_ps(dict_table_t *table)
|
||||
{
|
||||
index_fetch_t index_fetch_arg;
|
||||
pars_info_t* pinfo;
|
||||
@ -3491,7 +3489,7 @@ dict_stats_fetch_from_ps(
|
||||
dict_table_t* index_stats = dict_table_open_on_name(
|
||||
INDEX_STATS_NAME, false, DICT_ERR_IGNORE_NONE);
|
||||
if (!index_stats) {
|
||||
dict_table_close(table_stats);
|
||||
table_stats->release();
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
|
||||
@ -3501,13 +3499,13 @@ dict_stats_fetch_from_ps(
|
||||
if (!table_stats
|
||||
|| strcmp(table_stats->name.m_name, TABLE_STATS_NAME)) {
|
||||
release_and_exit:
|
||||
dict_sys.unfreeze();
|
||||
if (table_stats) {
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
}
|
||||
if (index_stats) {
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
}
|
||||
dict_sys.unfreeze();
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
|
||||
@ -3609,8 +3607,8 @@ release_and_exit:
|
||||
que_run_threads(que_fork_start_command(graph));
|
||||
que_graph_free(graph);
|
||||
|
||||
dict_table_close(table_stats, false, thd, mdl_table);
|
||||
dict_table_close(index_stats, false, thd, mdl_index);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
dberr_t ret = trx->error_state;
|
||||
@ -3630,252 +3628,46 @@ dict_stats_update_for_index(
|
||||
/*========================*/
|
||||
dict_index_t* index) /*!< in/out: index */
|
||||
{
|
||||
DBUG_ENTER("dict_stats_update_for_index");
|
||||
dict_table_t *const table= index->table;
|
||||
ut_ad(table->stat_initialized());
|
||||
|
||||
ut_ad(index->table->stat_initialized());
|
||||
|
||||
if (index->table->stats_is_persistent()) {
|
||||
|
||||
if (dict_stats_persistent_storage_check(false)) {
|
||||
index_stats_t stats = dict_stats_analyze_index(index);
|
||||
index->table->stats_mutex_lock();
|
||||
index->stat_index_size = stats.index_size;
|
||||
index->stat_n_leaf_pages = stats.n_leaf_pages;
|
||||
for (size_t i = 0; i < stats.stats.size(); ++i) {
|
||||
index->stat_n_diff_key_vals[i]
|
||||
= stats.stats[i].n_diff_key_vals;
|
||||
index->stat_n_sample_sizes[i]
|
||||
= stats.stats[i].n_sample_sizes;
|
||||
index->stat_n_non_null_key_vals[i]
|
||||
= stats.stats[i].n_non_null_key_vals;
|
||||
}
|
||||
index->table->stat_sum_of_other_index_sizes
|
||||
+= index->stat_index_size;
|
||||
index->table->stats_mutex_unlock();
|
||||
|
||||
dict_stats_save(index->table, &index->id);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
/* else */
|
||||
|
||||
if (innodb_index_stats_not_found == false &&
|
||||
index->stats_error_printed == false) {
|
||||
/* Fall back to transient stats since the persistent
|
||||
storage is not present or is corrupted */
|
||||
|
||||
ib::info() << "Recalculation of persistent statistics"
|
||||
" requested for table " << index->table->name
|
||||
<< " index " << index->name
|
||||
<< " but the required"
|
||||
" persistent statistics storage is not present or is"
|
||||
" corrupted. Using transient stats instead.";
|
||||
index->stats_error_printed = false;
|
||||
}
|
||||
}
|
||||
|
||||
dict_stats_update_transient_for_index(index);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for table and index statistics. The statistics
|
||||
are used in query optimization.
|
||||
@return DB_SUCCESS or error code
|
||||
@retval DB_SUCCESS_LOCKED_REC if the table under bulk insert operation */
|
||||
dberr_t
|
||||
dict_stats_update(
|
||||
/*==============*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
dict_stats_upd_option_t stats_upd_option)
|
||||
/*!< in: whether to (re) calc
|
||||
the stats or to fetch them from
|
||||
the persistent statistics
|
||||
storage */
|
||||
{
|
||||
ut_ad(!table->stats_mutex_is_owner());
|
||||
|
||||
if (!table->is_readable()) {
|
||||
return (dict_stats_report_error(table));
|
||||
} else if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
||||
/* If we have set a high innodb_force_recovery level, do
|
||||
not calculate statistics, as a badly corrupted index can
|
||||
cause a crash in it. */
|
||||
dict_stats_empty_table(table, false);
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
if (trx_id_t bulk_trx_id = table->bulk_trx_id) {
|
||||
if (trx_sys.find(nullptr, bulk_trx_id, false)) {
|
||||
dict_stats_empty_table(table, false);
|
||||
return DB_SUCCESS_LOCKED_REC;
|
||||
}
|
||||
}
|
||||
|
||||
switch (stats_upd_option) {
|
||||
case DICT_STATS_RECALC_PERSISTENT:
|
||||
|
||||
if (srv_read_only_mode) {
|
||||
goto transient;
|
||||
}
|
||||
|
||||
/* Persistent recalculation requested, called from
|
||||
1) ANALYZE TABLE, or
|
||||
2) the auto recalculation background thread, or
|
||||
3) open table if stats do not exist on disk and auto recalc
|
||||
is enabled */
|
||||
|
||||
/* InnoDB internal tables (e.g. SYS_TABLES) cannot have
|
||||
persistent stats enabled */
|
||||
ut_a(strchr(table->name.m_name, '/') != NULL);
|
||||
|
||||
/* check if the persistent statistics storage exists
|
||||
before calling the potentially slow function
|
||||
dict_stats_update_persistent(); that is a
|
||||
prerequisite for dict_stats_save() succeeding */
|
||||
if (dict_stats_persistent_storage_check(false)) {
|
||||
|
||||
dberr_t err;
|
||||
|
||||
err = dict_stats_update_persistent(table);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return(err);
|
||||
}
|
||||
|
||||
err = dict_stats_save(table, NULL);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/* Fall back to transient stats since the persistent
|
||||
storage is not present or is corrupted */
|
||||
|
||||
if (innodb_table_stats_not_found == false &&
|
||||
table->stats_error_printed == false) {
|
||||
ib::warn() << "Recalculation of persistent statistics"
|
||||
" requested for table "
|
||||
<< table->name
|
||||
<< " but the required persistent"
|
||||
" statistics storage is not present or is corrupted."
|
||||
" Using transient stats instead.";
|
||||
table->stats_error_printed = true;
|
||||
}
|
||||
|
||||
goto transient;
|
||||
|
||||
case DICT_STATS_RECALC_TRANSIENT:
|
||||
|
||||
goto transient;
|
||||
|
||||
case DICT_STATS_EMPTY_TABLE:
|
||||
|
||||
dict_stats_empty_table(table, true);
|
||||
|
||||
/* If table is using persistent stats,
|
||||
then save the stats on disk */
|
||||
|
||||
if (table->stats_is_persistent()) {
|
||||
|
||||
if (dict_stats_persistent_storage_check(false)) {
|
||||
|
||||
return(dict_stats_save(table, NULL));
|
||||
}
|
||||
|
||||
return(DB_STATS_DO_NOT_EXIST);
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
|
||||
case DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY:
|
||||
|
||||
/* fetch requested, either fetch from persistent statistics
|
||||
storage or use the old method */
|
||||
|
||||
if (table->stat_initialized()) {
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/* InnoDB internal tables (e.g. SYS_TABLES) cannot have
|
||||
persistent stats enabled */
|
||||
ut_a(strchr(table->name.m_name, '/') != NULL);
|
||||
|
||||
if (!dict_stats_persistent_storage_check(false)) {
|
||||
/* persistent statistics storage does not exist
|
||||
or is corrupted, calculate the transient stats */
|
||||
|
||||
if (innodb_table_stats_not_found == false &&
|
||||
table->stats_error_printed == false &&
|
||||
!opt_bootstrap) {
|
||||
ib::error() << "Fetch of persistent statistics"
|
||||
" requested for table "
|
||||
<< table->name
|
||||
<< " but the required system tables "
|
||||
<< TABLE_STATS_NAME_PRINT
|
||||
<< " and " << INDEX_STATS_NAME_PRINT
|
||||
<< " are not present or have unexpected"
|
||||
" structure. Using transient stats instead.";
|
||||
table->stats_error_printed = true;
|
||||
}
|
||||
|
||||
goto transient;
|
||||
}
|
||||
|
||||
dberr_t err = dict_stats_fetch_from_ps(table);
|
||||
|
||||
switch (err) {
|
||||
case DB_SUCCESS:
|
||||
return(DB_SUCCESS);
|
||||
case DB_STATS_DO_NOT_EXIST:
|
||||
|
||||
if (srv_read_only_mode) {
|
||||
goto transient;
|
||||
}
|
||||
#ifdef WITH_WSREP
|
||||
if (wsrep_thd_skip_locking(current_thd)) {
|
||||
goto transient;
|
||||
}
|
||||
if (table->stats_is_persistent())
|
||||
switch (dict_stats_persistent_storage_check(false)) {
|
||||
case SCHEMA_NOT_EXIST:
|
||||
break;
|
||||
case SCHEMA_INVALID:
|
||||
if (table->stats_error_printed)
|
||||
break;
|
||||
table->stats_error_printed= true;
|
||||
sql_print_information("InnoDB: Recalculation of persistent statistics"
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
" requested for table %.*s.%s index %s but"
|
||||
#else
|
||||
" requested for table %`.*s.%`s index %`s but"
|
||||
#endif
|
||||
if (table->stats_is_auto_recalc()) {
|
||||
return(dict_stats_update(
|
||||
table,
|
||||
DICT_STATS_RECALC_PERSISTENT));
|
||||
}
|
||||
" the required persistent statistics storage"
|
||||
" is corrupted. Using transient stats instead.",
|
||||
int(table->name.dblen()), table->name.m_name,
|
||||
table->name.basename(), index->name());
|
||||
break;
|
||||
case SCHEMA_OK:
|
||||
index_stats_t stats{dict_stats_analyze_index(index)};
|
||||
table->stats_mutex_lock();
|
||||
index->stat_index_size = stats.index_size;
|
||||
index->stat_n_leaf_pages = stats.n_leaf_pages;
|
||||
for (size_t i = 0; i < stats.stats.size(); ++i)
|
||||
{
|
||||
index->stat_n_diff_key_vals[i]= stats.stats[i].n_diff_key_vals;
|
||||
index->stat_n_sample_sizes[i]= stats.stats[i].n_sample_sizes;
|
||||
index->stat_n_non_null_key_vals[i]= stats.stats[i].n_non_null_key_vals;
|
||||
}
|
||||
table->stat_sum_of_other_index_sizes+= index->stat_index_size;
|
||||
table->stats_mutex_unlock();
|
||||
dict_stats_save(table, index->id);
|
||||
return;
|
||||
}
|
||||
|
||||
ib::info() << "Trying to use table " << table->name
|
||||
<< " which has persistent statistics enabled,"
|
||||
" but auto recalculation turned off and the"
|
||||
" statistics do not exist in "
|
||||
TABLE_STATS_NAME_PRINT
|
||||
" and " INDEX_STATS_NAME_PRINT
|
||||
". Please either run \"ANALYZE TABLE "
|
||||
<< table->name << ";\" manually or enable the"
|
||||
" auto recalculation with \"ALTER TABLE "
|
||||
<< table->name << " STATS_AUTO_RECALC=1;\"."
|
||||
" InnoDB will now use transient statistics for "
|
||||
<< table->name << ".";
|
||||
|
||||
goto transient;
|
||||
default:
|
||||
|
||||
if (innodb_table_stats_not_found == false &&
|
||||
table->stats_error_printed == false) {
|
||||
ib::error() << "Error fetching persistent statistics"
|
||||
" for table "
|
||||
<< table->name
|
||||
<< " from " TABLE_STATS_NAME_PRINT " and "
|
||||
INDEX_STATS_NAME_PRINT ": " << err
|
||||
<< ". Using transient stats method instead.";
|
||||
}
|
||||
|
||||
goto transient;
|
||||
}
|
||||
/* no "default:" in order to produce a compilation warning
|
||||
about unhandled enumeration value */
|
||||
}
|
||||
|
||||
transient:
|
||||
return dict_stats_update_transient(table);
|
||||
dict_stats_update_transient_for_index(index);
|
||||
}
|
||||
|
||||
/** Execute DELETE FROM mysql.innodb_table_stats
|
||||
@ -4025,7 +3817,7 @@ dberr_t dict_stats_rename_index(const char *db, const char *table,
|
||||
const char *old_name, const char *new_name,
|
||||
trx_t *trx)
|
||||
{
|
||||
if (!dict_stats_persistent_storage_check(true))
|
||||
if (dict_stats_persistent_storage_check(true) != SCHEMA_OK)
|
||||
return DB_STATS_DO_NOT_EXIST;
|
||||
pars_info_t *pinfo= pars_info_create();
|
||||
|
||||
@ -4161,7 +3953,7 @@ test_dict_stats_save()
|
||||
index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE;
|
||||
index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE;
|
||||
|
||||
ret = dict_stats_save(&table, NULL);
|
||||
ret = dict_stats_save(&table);
|
||||
|
||||
ut_a(ret == DB_SUCCESS);
|
||||
|
||||
|
@ -201,7 +201,7 @@ void dict_stats_update_if_needed_func(dict_table_t *table)
|
||||
|
||||
if (counter > threshold) {
|
||||
/* this will reset table->stat_modified_counter to 0 */
|
||||
dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT);
|
||||
dict_stats_update_transient(table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +329,7 @@ invalid_table_id:
|
||||
|
||||
if (!mdl || !table->is_accessible())
|
||||
{
|
||||
dict_table_close(table, false, thd, mdl);
|
||||
dict_table_close(table, thd, mdl);
|
||||
goto invalid_table_id;
|
||||
}
|
||||
|
||||
@ -343,10 +343,10 @@ invalid_table_id:
|
||||
difftime(time(nullptr), table->stats_last_recalc) >= MIN_RECALC_INTERVAL;
|
||||
|
||||
const dberr_t err= update_now
|
||||
? dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT)
|
||||
? dict_stats_update_persistent_try(table)
|
||||
: DB_SUCCESS_LOCKED_REC;
|
||||
|
||||
dict_table_close(table, false, thd, mdl);
|
||||
dict_table_close(table, thd, mdl);
|
||||
|
||||
mysql_mutex_lock(&recalc_pool_mutex);
|
||||
auto i= std::find_if(recalc_pool.begin(), recalc_pool.end(),
|
||||
|
@ -2809,7 +2809,7 @@ static void fts_optimize_sync_table(dict_table_t *table,
|
||||
std::this_thread::sleep_for(std::chrono::seconds(6)););
|
||||
|
||||
if (mdl_ticket)
|
||||
dict_table_close(sync_table, false, fts_opt_thd, mdl_ticket);
|
||||
dict_table_close(sync_table, fts_opt_thd, mdl_ticket);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
@ -1464,9 +1464,9 @@ static void innodb_drop_database(handlerton*, char *path)
|
||||
trx->commit();
|
||||
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
trx->free();
|
||||
@ -1620,7 +1620,7 @@ inline void ha_innobase::reload_statistics()
|
||||
if (dict_table_t *table= m_prebuilt ? m_prebuilt->table : nullptr)
|
||||
{
|
||||
if (table->is_readable())
|
||||
dict_stats_init(table);
|
||||
statistics_init(table, true);
|
||||
else
|
||||
table->stat.fetch_or(dict_table_t::STATS_INITIALIZED);
|
||||
}
|
||||
@ -1932,7 +1932,7 @@ static int innodb_check_version(handlerton *hton, const char *path,
|
||||
{
|
||||
const trx_id_t trx_id= table->def_trx_id;
|
||||
DBUG_ASSERT(trx_id <= create_id);
|
||||
dict_table_close(table);
|
||||
table->release();
|
||||
DBUG_PRINT("info", ("create_id: %llu trx_id: %" PRIu64, create_id, trx_id));
|
||||
DBUG_RETURN(create_id != trx_id);
|
||||
}
|
||||
@ -3010,7 +3010,7 @@ static bool innodb_copy_stat_flags(dict_table_t *table,
|
||||
dict_table_t::STATS_AUTO_RECALC_OFF, "");
|
||||
static_assert(true == dict_table_t::STATS_INITIALIZED, "");
|
||||
stat|= (sar & (HA_STATS_AUTO_RECALC_ON | HA_STATS_AUTO_RECALC_OFF)) << 3 |
|
||||
initialized;
|
||||
uint32_t(initialized);
|
||||
|
||||
table->stat= stat;
|
||||
return true;
|
||||
@ -3288,7 +3288,7 @@ static bool innobase_query_caching_table_check(
|
||||
|
||||
bool allow = innobase_query_caching_table_check_low(table, trx);
|
||||
|
||||
dict_table_close(table);
|
||||
table->release();
|
||||
|
||||
if (allow) {
|
||||
/* If the isolation level is high, assign a read view for the
|
||||
@ -5837,6 +5837,70 @@ static void initialize_auto_increment(dict_table_t *table, const Field& field,
|
||||
table->autoinc_mutex.wr_unlock();
|
||||
}
|
||||
|
||||
dberr_t ha_innobase::statistics_init(dict_table_t *table, bool recalc)
|
||||
{
|
||||
ut_ad(table->is_readable());
|
||||
ut_ad(!table->stats_mutex_is_owner());
|
||||
|
||||
uint32_t stat= table->stat;
|
||||
dberr_t err= DB_SUCCESS;
|
||||
|
||||
if (!recalc && dict_table_t::stat_initialized(stat));
|
||||
else if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN)
|
||||
dict_stats_empty_table(table, false);
|
||||
else
|
||||
{
|
||||
if (dict_table_t::stats_is_persistent(stat) && !srv_read_only_mode
|
||||
#ifdef WITH_WSREP
|
||||
&& !wsrep_thd_skip_locking(m_user_thd)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
switch (dict_stats_persistent_storage_check(false)) {
|
||||
case SCHEMA_OK:
|
||||
if (recalc)
|
||||
{
|
||||
recalc:
|
||||
err= dict_stats_update_persistent(table);
|
||||
if (err == DB_SUCCESS)
|
||||
err= dict_stats_save(table);
|
||||
}
|
||||
else
|
||||
{
|
||||
err= dict_stats_fetch_from_ps(table);
|
||||
if (err == DB_STATS_DO_NOT_EXIST && table->stats_is_auto_recalc())
|
||||
goto recalc;
|
||||
}
|
||||
if (err == DB_SUCCESS)
|
||||
return err;
|
||||
if (!recalc)
|
||||
break;
|
||||
/* fall through */
|
||||
case SCHEMA_INVALID:
|
||||
if (table->stats_error_printed)
|
||||
break;
|
||||
table->stats_error_printed = true;
|
||||
if (opt_bootstrap)
|
||||
break;
|
||||
sql_print_warning("InnoDB: %s of persistent statistics requested"
|
||||
" for table %`.*s.%`s"
|
||||
" but the required persistent statistics storage"
|
||||
" is corrupted.",
|
||||
recalc ? "Recalculation" : "Fetch",
|
||||
int(table->name.dblen()), table->name.m_name,
|
||||
table->name.basename());
|
||||
/* fall through */
|
||||
case SCHEMA_NOT_EXIST:
|
||||
err= DB_STATS_DO_NOT_EXIST;
|
||||
}
|
||||
}
|
||||
|
||||
dict_stats_update_transient(table);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/** Open an InnoDB table
|
||||
@param[in] name table name
|
||||
@return error code
|
||||
@ -13338,7 +13402,7 @@ ha_innobase::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info,
|
||||
|
||||
if (!error)
|
||||
{
|
||||
dict_stats_update(info.table(), DICT_STATS_EMPTY_TABLE);
|
||||
dict_stats_empty_table_and_save(info.table());
|
||||
if (!info.table()->is_temporary())
|
||||
log_write_up_to(trx->commit_lsn, true);
|
||||
info.table()->release();
|
||||
@ -13462,23 +13526,17 @@ ha_innobase::discard_or_import_tablespace(
|
||||
err, m_prebuilt->table->flags, NULL));
|
||||
}
|
||||
|
||||
if (m_prebuilt->table->stats_is_persistent()) {
|
||||
dberr_t ret;
|
||||
dict_table_t* t = m_prebuilt->table;
|
||||
|
||||
/* Adjust the persistent statistics. */
|
||||
ret = dict_stats_update(m_prebuilt->table,
|
||||
DICT_STATS_RECALC_PERSISTENT);
|
||||
|
||||
if (ret != DB_SUCCESS) {
|
||||
push_warning_printf(
|
||||
ha_thd(),
|
||||
Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_ALTER_INFO,
|
||||
"Error updating stats for table '%s'"
|
||||
" after table rebuild: %s",
|
||||
m_prebuilt->table->name.m_name,
|
||||
ut_strerr(ret));
|
||||
}
|
||||
if (dberr_t ret = dict_stats_update_persistent_try(t)) {
|
||||
push_warning_printf(
|
||||
ha_thd(),
|
||||
Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_ALTER_INFO,
|
||||
"Error updating stats after"
|
||||
" ALTER TABLE %`.*s.%`s IMPORT TABLESPACE: %s",
|
||||
int(t->name.dblen()), t->name.m_name,
|
||||
t->name.basename(), ut_strerr(ret));
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
@ -13700,8 +13758,8 @@ int ha_innobase::delete_table(const char *name)
|
||||
ut_ad(err == DB_LOCK_WAIT);
|
||||
ut_ad(trx->error_state == DB_SUCCESS);
|
||||
err= DB_SUCCESS;
|
||||
dict_table_close(table_stats, false, thd, mdl_table);
|
||||
dict_table_close(index_stats, false, thd, mdl_index);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
table_stats= nullptr;
|
||||
index_stats= nullptr;
|
||||
}
|
||||
@ -13775,9 +13833,9 @@ err_exit:
|
||||
purge_sys.resume_FTS();
|
||||
#endif
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
if (trx != parent_trx)
|
||||
trx->free();
|
||||
@ -13807,9 +13865,9 @@ err_exit:
|
||||
std::vector<pfs_os_file_t> deleted;
|
||||
trx->commit(deleted);
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
for (pfs_os_file_t d : deleted)
|
||||
os_file_close(d);
|
||||
@ -14024,15 +14082,18 @@ int ha_innobase::truncate()
|
||||
error= fts_lock_tables(trx, *ib_table);
|
||||
}
|
||||
|
||||
/* Wait for purge threads to stop using the table. */
|
||||
for (uint n = 15; ib_table->get_ref_count() > 1; )
|
||||
if (error == DB_SUCCESS)
|
||||
{
|
||||
if (!--n)
|
||||
/* Wait for purge threads to stop using the table. */
|
||||
for (uint n = 15; ib_table->get_ref_count() > 1; )
|
||||
{
|
||||
error= DB_LOCK_WAIT_TIMEOUT;
|
||||
break;
|
||||
if (!--n)
|
||||
{
|
||||
error= DB_LOCK_WAIT_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
if (error == DB_SUCCESS && ib_table->stats_is_persistent() &&
|
||||
@ -14125,7 +14186,7 @@ int ha_innobase::truncate()
|
||||
|
||||
if (!err)
|
||||
{
|
||||
dict_stats_update(m_prebuilt->table, DICT_STATS_EMPTY_TABLE);
|
||||
dict_stats_empty_table_and_save(m_prebuilt->table);
|
||||
log_write_up_to(trx->commit_lsn, true);
|
||||
row_prebuilt_t *prebuilt= m_prebuilt;
|
||||
uchar *upd_buf= m_upd_buf;
|
||||
@ -14157,13 +14218,49 @@ int ha_innobase::truncate()
|
||||
mem_heap_free(heap);
|
||||
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, false, m_user_thd, mdl_table);
|
||||
dict_table_close(table_stats, m_user_thd, mdl_table);
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, false, m_user_thd, mdl_index);
|
||||
dict_table_close(index_stats, m_user_thd, mdl_index);
|
||||
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
|
||||
/** Deinitialize InnoDB persistent statistics, forcing them
|
||||
to be reloaded on subsequent ha_innobase::open().
|
||||
@param t table for which the cached STATS_PERSISTENT are to be evicted */
|
||||
static void stats_deinit(dict_table_t *t) noexcept
|
||||
{
|
||||
ut_ad(dict_sys.frozen());
|
||||
ut_ad(t->get_ref_count() == 0);
|
||||
|
||||
if (t->is_temporary() || t->no_rollback())
|
||||
return;
|
||||
|
||||
t->stats_mutex_lock();
|
||||
t->stat= t->stat & ~dict_table_t::STATS_INITIALIZED;
|
||||
MEM_UNDEFINED(&t->stat_n_rows, sizeof t->stat_n_rows);
|
||||
MEM_UNDEFINED(&t->stat_clustered_index_size,
|
||||
sizeof t->stat_clustered_index_size);
|
||||
MEM_UNDEFINED(&t->stat_sum_of_other_index_sizes,
|
||||
sizeof t->stat_sum_of_other_index_sizes);
|
||||
MEM_UNDEFINED(&t->stat_modified_counter, sizeof t->stat_modified_counter);
|
||||
#ifdef HAVE_valgrind
|
||||
for (dict_index_t *i= dict_table_get_first_index(t); i;
|
||||
i= dict_table_get_next_index(i))
|
||||
{
|
||||
MEM_UNDEFINED(i->stat_n_diff_key_vals,
|
||||
i->n_uniq * sizeof *i->stat_n_diff_key_vals);
|
||||
MEM_UNDEFINED(i->stat_n_sample_sizes,
|
||||
i->n_uniq * sizeof *i->stat_n_sample_sizes);
|
||||
MEM_UNDEFINED(i->stat_n_non_null_key_vals,
|
||||
i->n_uniq * sizeof *i->stat_n_non_null_key_vals);
|
||||
MEM_UNDEFINED(&i->stat_index_size, sizeof i->stat_index_size);
|
||||
MEM_UNDEFINED(&i->stat_n_leaf_pages, sizeof i->stat_n_leaf_pages);
|
||||
}
|
||||
#endif /* HAVE_valgrind */
|
||||
t->stats_mutex_unlock();
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Renames an InnoDB table.
|
||||
@return 0 or error code */
|
||||
@ -14197,15 +14294,20 @@ ha_innobase::rename_table(
|
||||
dberr_t error = DB_SUCCESS;
|
||||
const bool from_temp = dict_table_t::is_temporary_name(norm_from);
|
||||
|
||||
dict_table_t* t;
|
||||
|
||||
if (from_temp) {
|
||||
/* There is no need to lock any FOREIGN KEY child tables. */
|
||||
} else if (dict_table_t *table = dict_table_open_on_name(
|
||||
norm_from, false, DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||
error = lock_table_children(table, trx);
|
||||
if (error == DB_SUCCESS) {
|
||||
error = lock_table_for_trx(table, trx, LOCK_X);
|
||||
t = nullptr;
|
||||
} else {
|
||||
t = dict_table_open_on_name(
|
||||
norm_from, false, DICT_ERR_IGNORE_FK_NOKEY);
|
||||
if (t) {
|
||||
error = lock_table_children(t, trx);
|
||||
if (error == DB_SUCCESS) {
|
||||
error = lock_table_for_trx(t, trx, LOCK_X);
|
||||
}
|
||||
}
|
||||
table->release();
|
||||
}
|
||||
|
||||
if (strcmp(norm_from, TABLE_STATS_NAME)
|
||||
@ -14246,10 +14348,8 @@ ha_innobase::rename_table(
|
||||
we cannot lock the tables, when the
|
||||
table is being renamed from from a
|
||||
temporary name. */
|
||||
dict_table_close(table_stats, false, thd,
|
||||
mdl_table);
|
||||
dict_table_close(index_stats, false, thd,
|
||||
mdl_index);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
table_stats = nullptr;
|
||||
index_stats = nullptr;
|
||||
}
|
||||
@ -14291,16 +14391,27 @@ ha_innobase::rename_table(
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
trx->flush_log_later = true;
|
||||
if (t) {
|
||||
ut_ad(dict_sys.frozen());
|
||||
if (UNIV_LIKELY(t->release())) {
|
||||
stats_deinit(t);
|
||||
} else {
|
||||
ut_ad("unexpected references" == 0);
|
||||
}
|
||||
}
|
||||
innobase_commit_low(trx);
|
||||
} else {
|
||||
if (t) {
|
||||
t->release();
|
||||
}
|
||||
trx->rollback();
|
||||
}
|
||||
|
||||
if (table_stats) {
|
||||
dict_table_close(table_stats, true, thd, mdl_table);
|
||||
dict_table_close(table_stats, thd, mdl_table);
|
||||
}
|
||||
if (index_stats) {
|
||||
dict_table_close(index_stats, true, thd, mdl_index);
|
||||
dict_table_close(index_stats, thd, mdl_index);
|
||||
}
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
if (error == DB_SUCCESS) {
|
||||
@ -14314,10 +14425,10 @@ ha_innobase::rename_table(
|
||||
during DDL operations, because the duplicate key would
|
||||
exist in metadata tables, not in the user table. */
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to);
|
||||
error = DB_ERROR;
|
||||
DBUG_RETURN(HA_ERR_GENERIC);
|
||||
} else if (error == DB_LOCK_WAIT_TIMEOUT) {
|
||||
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
|
||||
error = DB_LOCK_WAIT;
|
||||
DBUG_RETURN(HA_ERR_GENERIC);
|
||||
}
|
||||
|
||||
DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
|
||||
@ -14796,51 +14907,69 @@ ha_innobase::info_low(
|
||||
ib_table = m_prebuilt->table;
|
||||
DBUG_ASSERT(ib_table->get_ref_count() > 0);
|
||||
|
||||
if (!ib_table->is_readable()) {
|
||||
if (!ib_table->is_readable()
|
||||
|| srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
||||
dict_stats_empty_table(ib_table, true);
|
||||
}
|
||||
} else if (flag & HA_STATUS_TIME) {
|
||||
stats.update_time = ib_table->update_time;
|
||||
if (!is_analyze && !innobase_stats_on_metadata) {
|
||||
goto stats_fetch;
|
||||
}
|
||||
|
||||
if (flag & HA_STATUS_TIME) {
|
||||
if (is_analyze || innobase_stats_on_metadata) {
|
||||
dberr_t ret;
|
||||
m_prebuilt->trx->op_info = "updating table statistics";
|
||||
|
||||
dict_stats_upd_option_t opt;
|
||||
dberr_t ret;
|
||||
|
||||
m_prebuilt->trx->op_info = "updating table statistics";
|
||||
|
||||
if (ib_table->stats_is_persistent()) {
|
||||
if (is_analyze) {
|
||||
if (!srv_read_only_mode) {
|
||||
dict_stats_recalc_pool_del(
|
||||
ib_table->id, false);
|
||||
}
|
||||
opt = DICT_STATS_RECALC_PERSISTENT;
|
||||
} else {
|
||||
/* This is e.g. 'SHOW INDEXES', fetch
|
||||
the persistent stats from disk. */
|
||||
opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY;
|
||||
}
|
||||
if (ib_table->stats_is_persistent()
|
||||
&& !srv_read_only_mode
|
||||
&& dict_stats_persistent_storage_check(false)
|
||||
== SCHEMA_OK) {
|
||||
if (is_analyze) {
|
||||
dict_stats_recalc_pool_del(ib_table->id,
|
||||
false);
|
||||
recalc:
|
||||
ret = statistics_init(ib_table, is_analyze);
|
||||
} else {
|
||||
opt = DICT_STATS_RECALC_TRANSIENT;
|
||||
/* This is e.g. 'SHOW INDEXES' */
|
||||
ret = statistics_init(ib_table, is_analyze);
|
||||
switch (ret) {
|
||||
case DB_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
case DB_STATS_DO_NOT_EXIST:
|
||||
if (!ib_table
|
||||
->stats_is_auto_recalc()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt_bootstrap) {
|
||||
break;
|
||||
}
|
||||
#ifdef WITH_WSREP
|
||||
if (wsrep_thd_skip_locking(
|
||||
m_user_thd)) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
is_analyze = true;
|
||||
goto recalc;
|
||||
}
|
||||
}
|
||||
|
||||
ret = dict_stats_update(ib_table, opt);
|
||||
|
||||
} else {
|
||||
ret = dict_stats_update_transient(ib_table);
|
||||
if (ret != DB_SUCCESS) {
|
||||
error:
|
||||
m_prebuilt->trx->op_info = "";
|
||||
DBUG_RETURN(HA_ERR_GENERIC);
|
||||
}
|
||||
|
||||
m_prebuilt->trx->op_info =
|
||||
"returning various info to MariaDB";
|
||||
}
|
||||
|
||||
|
||||
stats.update_time = (ulong) ib_table->update_time;
|
||||
m_prebuilt->trx->op_info = "returning various info to MariaDB";
|
||||
} else {
|
||||
stats_fetch:
|
||||
statistics_init(ib_table, false);
|
||||
}
|
||||
|
||||
dict_stats_init(ib_table);
|
||||
|
||||
if (flag & HA_STATUS_VARIABLE) {
|
||||
|
||||
ulint stat_clustered_index_size;
|
||||
@ -15696,7 +15825,7 @@ get_foreign_key_info(
|
||||
<< foreign->foreign_table_name;
|
||||
}
|
||||
} else {
|
||||
dict_table_close(ref_table, true);
|
||||
ref_table->release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -17581,7 +17710,7 @@ static int innodb_ft_aux_table_validate(THD *thd, st_mysql_sys_var*,
|
||||
table_name, false, DICT_ERR_IGNORE_NONE)) {
|
||||
const table_id_t id = dict_table_has_fts_index(table)
|
||||
? table->id : 0;
|
||||
dict_table_close(table);
|
||||
table->release();
|
||||
if (id) {
|
||||
innodb_ft_aux_table_id = id;
|
||||
if (table_name == buf) {
|
||||
|
@ -101,6 +101,9 @@ public:
|
||||
|
||||
int open(const char *name, int mode, uint test_if_locked) override;
|
||||
|
||||
/** Fetch or recalculate InnoDB table statistics */
|
||||
dberr_t statistics_init(dict_table_t *table, bool recalc);
|
||||
|
||||
handler* clone(const char *name, MEM_ROOT *mem_root) override;
|
||||
|
||||
int close(void) override;
|
||||
|
@ -7542,10 +7542,11 @@ error_handled:
|
||||
}
|
||||
}
|
||||
|
||||
/* n_ref_count must be 1, because background threads cannot
|
||||
/* n_ref_count must be 1 (+ InnoDB_share),
|
||||
because background threads cannot
|
||||
be executing on this very table as we are
|
||||
holding MDL_EXCLUSIVE. */
|
||||
ut_ad(ctx->online || user_table->get_ref_count() == 1);
|
||||
ut_ad(ctx->online || ((user_table->get_ref_count() - 1) <= 1));
|
||||
|
||||
if (new_clustered) {
|
||||
online_retry_drop_indexes_low(user_table, ctx->trx);
|
||||
@ -11180,7 +11181,10 @@ alter_stats_norebuild(
|
||||
DBUG_ENTER("alter_stats_norebuild");
|
||||
DBUG_ASSERT(!ctx->need_rebuild());
|
||||
|
||||
if (!ctx->new_table->stats_is_persistent()) {
|
||||
auto stat = ctx->new_table->stat;
|
||||
|
||||
if (!dict_table_t::stat_initialized(stat)
|
||||
|| !dict_table_t::stats_is_persistent(stat)) {
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -11189,7 +11193,6 @@ alter_stats_norebuild(
|
||||
DBUG_ASSERT(index->table == ctx->new_table);
|
||||
|
||||
if (!(index->type & DICT_FTS)) {
|
||||
dict_stats_init(ctx->new_table);
|
||||
dict_stats_update_for_index(index);
|
||||
}
|
||||
}
|
||||
@ -11214,11 +11217,15 @@ alter_stats_rebuild(
|
||||
{
|
||||
DBUG_ENTER("alter_stats_rebuild");
|
||||
|
||||
if (!table->space || !table->stats_is_persistent()) {
|
||||
if (!table->space || !table->stats_is_persistent()
|
||||
|| dict_stats_persistent_storage_check(false) != SCHEMA_OK) {
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
dberr_t ret = dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT);
|
||||
dberr_t ret = dict_stats_update_persistent(table);
|
||||
if (ret == DB_SUCCESS) {
|
||||
ret = dict_stats_save(table);
|
||||
}
|
||||
|
||||
if (ret != DB_SUCCESS) {
|
||||
push_warning_printf(
|
||||
@ -11331,6 +11338,13 @@ ha_innobase::commit_inplace_alter_table(
|
||||
/* A rollback is being requested. So far we may at
|
||||
most have created stubs for ADD INDEX or a copy of the
|
||||
table for rebuild. */
|
||||
#if 0 /* FIXME: is there a better way for innodb.innodb-index-online? */
|
||||
lock_shared_ha_data();
|
||||
auto share = static_cast<InnoDB_share*>(get_ha_share_ptr());
|
||||
set_ha_share_ptr(nullptr);
|
||||
unlock_shared_ha_data();
|
||||
delete share;
|
||||
#endif
|
||||
DBUG_RETURN(rollback_inplace_alter_table(
|
||||
ha_alter_info, table, m_prebuilt));
|
||||
}
|
||||
@ -11600,12 +11614,10 @@ err_index:
|
||||
}
|
||||
if (error != DB_SUCCESS) {
|
||||
if (table_stats) {
|
||||
dict_table_close(table_stats, false, m_user_thd,
|
||||
mdl_table);
|
||||
dict_table_close(table_stats, m_user_thd, mdl_table);
|
||||
}
|
||||
if (index_stats) {
|
||||
dict_table_close(index_stats, false, m_user_thd,
|
||||
mdl_index);
|
||||
dict_table_close(index_stats, m_user_thd, mdl_index);
|
||||
}
|
||||
my_error_innodb(error, table_share->table_name.str, 0);
|
||||
if (fts_exist) {
|
||||
@ -11641,11 +11653,11 @@ fail:
|
||||
trx->rollback();
|
||||
ut_ad(!trx->fts_trx);
|
||||
if (table_stats) {
|
||||
dict_table_close(table_stats, true, m_user_thd,
|
||||
dict_table_close(table_stats, m_user_thd,
|
||||
mdl_table);
|
||||
}
|
||||
if (index_stats) {
|
||||
dict_table_close(index_stats, true, m_user_thd,
|
||||
dict_table_close(index_stats, m_user_thd,
|
||||
mdl_index);
|
||||
}
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
@ -11699,10 +11711,10 @@ fail:
|
||||
}
|
||||
|
||||
if (table_stats) {
|
||||
dict_table_close(table_stats, true, m_user_thd, mdl_table);
|
||||
dict_table_close(table_stats, m_user_thd, mdl_table);
|
||||
}
|
||||
if (index_stats) {
|
||||
dict_table_close(index_stats, true, m_user_thd, mdl_index);
|
||||
dict_table_close(index_stats, m_user_thd, mdl_index);
|
||||
}
|
||||
|
||||
/* Commit or roll back the changes to the data dictionary. */
|
||||
|
@ -2230,7 +2230,7 @@ i_s_fts_deleted_generic_fill(
|
||||
DBUG_RETURN(0);
|
||||
} else if (!dict_table_has_fts_index(user_table)
|
||||
|| !user_table->is_readable()) {
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -2245,7 +2245,7 @@ i_s_fts_deleted_generic_fill(
|
||||
|
||||
fts_table_fetch_doc_ids(trx, &fts_table, deleted);
|
||||
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
|
||||
trx->free();
|
||||
|
||||
@ -2578,7 +2578,7 @@ i_s_fts_index_cache_fill(
|
||||
}
|
||||
|
||||
if (!user_table->fts || !user_table->fts->cache) {
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -2603,7 +2603,7 @@ i_s_fts_index_cache_fill(
|
||||
}
|
||||
|
||||
mysql_mutex_unlock(&cache->lock);
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
@ -3020,7 +3020,7 @@ i_s_fts_index_table_fill(
|
||||
}
|
||||
}
|
||||
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
|
||||
ut_free(conv_str.f_str);
|
||||
|
||||
@ -3145,7 +3145,7 @@ i_s_fts_config_fill(
|
||||
}
|
||||
|
||||
if (!dict_table_has_fts_index(user_table)) {
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -3202,7 +3202,7 @@ i_s_fts_config_fill(
|
||||
|
||||
fts_sql_commit(trx);
|
||||
|
||||
dict_table_close(user_table, false, thd, mdl_ticket);
|
||||
dict_table_close(user_table, thd, mdl_ticket);
|
||||
|
||||
trx->free();
|
||||
|
||||
|
@ -146,21 +146,21 @@ dict_table_open_on_id(table_id_t table_id, bool dict_locked,
|
||||
MDL_ticket **mdl= nullptr)
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/** Decrement the count of open handles */
|
||||
void dict_table_close(dict_table_t *table);
|
||||
/** Release a metadata lock.
|
||||
@param thd connection that holds mdl
|
||||
@param mdl metadata lock, or nullptr */
|
||||
void mdl_release(THD *thd, MDL_ticket *mdl) noexcept;
|
||||
|
||||
/** Decrements the count of open handles of a table.
|
||||
@param[in,out] table table
|
||||
@param[in] dict_locked whether dict_sys.latch is being held
|
||||
@param[in] thd thread to release MDL
|
||||
@param[in] mdl metadata lock or NULL if the thread is a
|
||||
foreground one. */
|
||||
void
|
||||
dict_table_close(
|
||||
dict_table_t* table,
|
||||
bool dict_locked,
|
||||
THD* thd = NULL,
|
||||
MDL_ticket* mdl = NULL);
|
||||
/** Release a table reference and a metadata lock.
|
||||
@param table referenced table
|
||||
@param thd connection that holds mdl
|
||||
@param mdl metadata lock, or nullptr */
|
||||
inline void dict_table_close(dict_table_t* table, THD *thd, MDL_ticket *mdl)
|
||||
noexcept
|
||||
{
|
||||
table->release();
|
||||
mdl_release(thd, mdl);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Gets the minimum number of bytes per character.
|
||||
|
@ -1076,8 +1076,8 @@ dict_table_is_file_per_table(
|
||||
/** Acquire the table handle. */
|
||||
inline void dict_table_t::acquire()
|
||||
{
|
||||
ut_ad(dict_sys.frozen());
|
||||
n_ref_count++;
|
||||
ut_d(const auto old=) n_ref_count++;
|
||||
ut_ad(old || dict_sys.frozen());
|
||||
}
|
||||
|
||||
/** Release the table handle.
|
||||
|
@ -1112,9 +1112,6 @@ struct dict_index_t {
|
||||
uint32_t stat_n_leaf_pages;
|
||||
/*!< approximate number of leaf pages in the
|
||||
index tree */
|
||||
bool stats_error_printed;
|
||||
/*!< has persistent statistics error printed
|
||||
for this index ? */
|
||||
/* @} */
|
||||
/** Statistics for defragmentation, these numbers are estimations and
|
||||
could be very inaccurate at certain times, e.g. right after restart,
|
||||
@ -2393,7 +2390,7 @@ public:
|
||||
ib_uint64_t stat_modified_counter;
|
||||
|
||||
bool stats_error_printed;
|
||||
/*!< Has persistent stats error beein
|
||||
/*!< Has persistent stats error been
|
||||
already printed for this table ? */
|
||||
/* @} */
|
||||
|
||||
|
@ -30,46 +30,6 @@ Created Jan 06, 2010 Vasil Dimov
|
||||
#include "dict0types.h"
|
||||
#include "trx0types.h"
|
||||
|
||||
enum dict_stats_upd_option_t {
|
||||
DICT_STATS_RECALC_PERSISTENT,/* (re) calculate the
|
||||
statistics using a precise and slow
|
||||
algo and save them to the persistent
|
||||
storage, if the persistent storage is
|
||||
not present then emit a warning and
|
||||
fall back to transient stats */
|
||||
DICT_STATS_RECALC_TRANSIENT,/* (re) calculate the statistics
|
||||
using an imprecise quick algo
|
||||
without saving the results
|
||||
persistently */
|
||||
DICT_STATS_EMPTY_TABLE, /* Write all zeros (or 1 where it makes sense)
|
||||
into a table and its indexes' statistics
|
||||
members. The resulting stats correspond to an
|
||||
empty table. If the table is using persistent
|
||||
statistics, then they are saved on disk. */
|
||||
DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY /* fetch the stats
|
||||
from the persistent storage if the in-memory
|
||||
structures have not been initialized yet,
|
||||
otherwise do nothing */
|
||||
};
|
||||
|
||||
/*********************************************************************//**
|
||||
Initialize table's stats for the first time when opening a table. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_init(
|
||||
/*============*/
|
||||
dict_table_t* table); /*!< in/out: table */
|
||||
|
||||
/*********************************************************************//**
|
||||
Deinitialize table's stats after the last close of the table. This is
|
||||
used to detect "FLUSH TABLE" and refresh the stats upon next open. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_deinit(
|
||||
/*==============*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
/** Update the table modification counter and if necessary,
|
||||
schedule new estimates for table and index statistics to be calculated.
|
||||
@ -86,19 +46,6 @@ void dict_stats_update_if_needed_func(dict_table_t *table)
|
||||
# define dict_stats_update_if_needed(t,trx) dict_stats_update_if_needed_func(t)
|
||||
#endif
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for table and index statistics. The statistics
|
||||
are used in query optimization.
|
||||
@return DB_* error code or DB_SUCCESS */
|
||||
dberr_t
|
||||
dict_stats_update(
|
||||
/*==============*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
dict_stats_upd_option_t stats_upd_option);
|
||||
/*!< in: whether to (re) calc
|
||||
the stats or to fetch them from
|
||||
the persistent storage */
|
||||
|
||||
/** Execute DELETE FROM mysql.innodb_table_stats
|
||||
@param database_name database name
|
||||
@param table_name table name
|
||||
@ -135,6 +82,50 @@ dict_stats_update_for_index(
|
||||
dict_index_t* index) /*!< in/out: index */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
|
||||
enum dict_stats_schema_check {
|
||||
/** The InnoDB persistent statistics tables do not exist. */
|
||||
SCHEMA_NOT_EXIST= -1,
|
||||
/** The schema of the InnoDB persistent statistics tables is valid. */
|
||||
SCHEMA_OK= 0,
|
||||
/** The schema is invalid. */
|
||||
SCHEMA_INVALID
|
||||
};
|
||||
|
||||
/** @return whether the persistent statistics storage is usable */
|
||||
dict_stats_schema_check
|
||||
dict_stats_persistent_storage_check(bool dict_already_locked= false) noexcept;
|
||||
|
||||
/** Save the persistent statistics of a table or an index.
|
||||
@param table table whose stats to save
|
||||
@param only_for_index the index ID to save statistics for (0=all)
|
||||
@return DB_SUCCESS or error code */
|
||||
dberr_t dict_stats_save(dict_table_t* table, index_id_t index_id= 0);
|
||||
|
||||
/** Read the stored persistent statistics of a table. */
|
||||
dberr_t dict_stats_fetch_from_ps(dict_table_t *table);
|
||||
|
||||
/**
|
||||
Calculate new estimates for table and index statistics. This function
|
||||
is relatively quick and is used to calculate non-persistent statistics.
|
||||
@param table table for which the non-persistent statistics are being updated
|
||||
@return error code
|
||||
@retval DB_SUCCESS_LOCKED REC if the table under bulk insert operation */
|
||||
dberr_t dict_stats_update_transient(dict_table_t *table) noexcept;
|
||||
|
||||
/**
|
||||
Calculate new estimates for table and index statistics. This function
|
||||
is slower than dict_stats_update_transient().
|
||||
@param table table for which the persistent statistics are being updated
|
||||
@return DB_SUCCESS or error code
|
||||
@retval DB_SUCCESS_LOCKED_REC if the table under bulk insert operation */
|
||||
dberr_t dict_stats_update_persistent(dict_table_t *table) noexcept;
|
||||
|
||||
/**
|
||||
Try to calculate and save new estimates for persistent statistics.
|
||||
If persistent statistics are not enabled for the table or not available,
|
||||
this does nothing. */
|
||||
dberr_t dict_stats_update_persistent_try(dict_table_t *table);
|
||||
|
||||
/** Rename a table in InnoDB persistent stats storage.
|
||||
@param old_name old table name
|
||||
@param new_name new table name
|
||||
@ -191,8 +182,6 @@ dberr_t
|
||||
dict_stats_report_error(dict_table_t* table, bool defragment = false)
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
#include "dict0stats.inl"
|
||||
|
||||
#ifdef UNIV_ENABLE_UNIT_TEST_DICT_STATS
|
||||
void test_dict_stats_all();
|
||||
#endif /* UNIV_ENABLE_UNIT_TEST_DICT_STATS */
|
||||
@ -206,4 +195,8 @@ void
|
||||
dict_stats_empty_table(
|
||||
dict_table_t* table,
|
||||
bool empty_defrag_stats);
|
||||
|
||||
/** Clear the statistics for a table and save them if
|
||||
persistent statistics are enabled. */
|
||||
void dict_stats_empty_table_and_save(dict_table_t *table);
|
||||
#endif /* dict0stats_h */
|
||||
|
@ -1,108 +0,0 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
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
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**************************************************//**
|
||||
@file include/dict0stats.ic
|
||||
Code used for calculating and manipulating table statistics.
|
||||
|
||||
Created Jan 23, 2012 Vasil Dimov
|
||||
*******************************************************/
|
||||
|
||||
#include "dict0dict.h"
|
||||
|
||||
/*********************************************************************//**
|
||||
Initialize table's stats for the first time when opening a table. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_init(
|
||||
/*============*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
{
|
||||
ut_ad(!table->stats_mutex_is_owner());
|
||||
|
||||
uint32_t stat = table->stat;
|
||||
|
||||
if (stat & dict_table_t::STATS_INITIALIZED) {
|
||||
return;
|
||||
}
|
||||
|
||||
dict_stats_upd_option_t opt;
|
||||
|
||||
if (table->stats_is_persistent(stat)) {
|
||||
opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY;
|
||||
} else {
|
||||
opt = DICT_STATS_RECALC_TRANSIENT;
|
||||
}
|
||||
|
||||
dict_stats_update(table, opt);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Deinitialize table's stats after the last close of the table. This is
|
||||
used to detect "FLUSH TABLE" and refresh the stats upon next open. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_deinit(
|
||||
/*==============*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
{
|
||||
ut_ad(table->stats_mutex_is_owner());
|
||||
ut_ad(table->get_ref_count() == 0);
|
||||
|
||||
#ifdef HAVE_valgrind
|
||||
if (!table->stat_initialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MEM_UNDEFINED(&table->stat_n_rows, sizeof table->stat_n_rows);
|
||||
MEM_UNDEFINED(&table->stat_clustered_index_size,
|
||||
sizeof table->stat_clustered_index_size);
|
||||
MEM_UNDEFINED(&table->stat_sum_of_other_index_sizes,
|
||||
sizeof table->stat_sum_of_other_index_sizes);
|
||||
MEM_UNDEFINED(&table->stat_modified_counter,
|
||||
sizeof table->stat_modified_counter);
|
||||
|
||||
dict_index_t* index;
|
||||
|
||||
for (index = dict_table_get_first_index(table);
|
||||
index != NULL;
|
||||
index = dict_table_get_next_index(index)) {
|
||||
MEM_UNDEFINED(
|
||||
index->stat_n_diff_key_vals,
|
||||
index->n_uniq
|
||||
* sizeof index->stat_n_diff_key_vals[0]);
|
||||
MEM_UNDEFINED(
|
||||
index->stat_n_sample_sizes,
|
||||
index->n_uniq
|
||||
* sizeof index->stat_n_sample_sizes[0]);
|
||||
MEM_UNDEFINED(
|
||||
index->stat_n_non_null_key_vals,
|
||||
index->n_uniq
|
||||
* sizeof index->stat_n_non_null_key_vals[0]);
|
||||
MEM_UNDEFINED(
|
||||
&index->stat_index_size,
|
||||
sizeof(index->stat_index_size));
|
||||
MEM_UNDEFINED(
|
||||
&index->stat_n_leaf_pages,
|
||||
sizeof(index->stat_n_leaf_pages));
|
||||
}
|
||||
#endif /* HAVE_valgrind */
|
||||
|
||||
table->stat = table->stat & ~dict_table_t::STATS_INITIALIZED;
|
||||
}
|
@ -1955,7 +1955,7 @@ row_ins_check_foreign_constraints(
|
||||
TRUE, foreign, table, ref_tuple, thr);
|
||||
|
||||
if (ref_table) {
|
||||
dict_table_close(ref_table);
|
||||
ref_table->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -981,7 +981,7 @@ void row_prebuilt_free(row_prebuilt_t *prebuilt)
|
||||
rtr_clean_rtr_info(prebuilt->rtr_info, true);
|
||||
}
|
||||
if (prebuilt->table) {
|
||||
dict_table_close(prebuilt->table);
|
||||
prebuilt->table->release();
|
||||
}
|
||||
|
||||
mem_heap_free(prebuilt->heap);
|
||||
|
@ -244,8 +244,7 @@ func_exit:
|
||||
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
|
||||
|
||||
if (UNIV_LIKELY_NULL(table)) {
|
||||
dict_table_close(table, dict_locked,
|
||||
node->trx->mysql_thd, mdl_ticket);
|
||||
dict_table_close(table, node->trx->mysql_thd, mdl_ticket);
|
||||
}
|
||||
|
||||
return(err);
|
||||
@ -452,7 +451,7 @@ close_table:
|
||||
would probably be better to just drop all temporary
|
||||
tables (and temporary undo log records) of the current
|
||||
connection, instead of doing this rollback. */
|
||||
dict_table_close(node->table, dict_locked);
|
||||
node->table->release();
|
||||
node->table = NULL;
|
||||
return false;
|
||||
} else {
|
||||
@ -644,8 +643,7 @@ row_undo_ins(
|
||||
break;
|
||||
}
|
||||
|
||||
dict_table_close(node->table, dict_locked);
|
||||
|
||||
node->table->release();
|
||||
node->table = NULL;
|
||||
|
||||
return(err);
|
||||
|
@ -1259,7 +1259,7 @@ close_table:
|
||||
would probably be better to just drop all temporary
|
||||
tables (and temporary undo log records) of the current
|
||||
connection, instead of doing this rollback. */
|
||||
dict_table_close(node->table, dict_locked);
|
||||
node->table->release();
|
||||
node->table = NULL;
|
||||
return false;
|
||||
}
|
||||
@ -1418,8 +1418,7 @@ rollback_clust:
|
||||
}
|
||||
}
|
||||
|
||||
dict_table_close(node->table, dict_locked);
|
||||
|
||||
node->table->release();
|
||||
node->table = NULL;
|
||||
|
||||
return(err);
|
||||
|
@ -253,7 +253,7 @@ row_upd_check_references_constraints(
|
||||
FALSE, foreign, table, entry, thr);
|
||||
|
||||
if (ref_table) {
|
||||
dict_table_close(ref_table);
|
||||
ref_table->release();
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
@ -338,7 +338,7 @@ wsrep_row_upd_check_foreign_constraints(
|
||||
TRUE, foreign, table, entry, thr);
|
||||
|
||||
if (opened) {
|
||||
dict_table_close(opened);
|
||||
opened->release();
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
@ -1060,7 +1060,7 @@ static void trx_purge_close_tables(purge_node_t *node, THD *thd)
|
||||
else if (t.second.first == reinterpret_cast<dict_table_t*>(-1));
|
||||
else
|
||||
{
|
||||
dict_table_close(t.second.first, false, thd, t.second.second);
|
||||
dict_table_close(t.second.first, thd, t.second.second);
|
||||
t.second.first= reinterpret_cast<dict_table_t*>(-1);
|
||||
}
|
||||
}
|
||||
@ -1198,7 +1198,7 @@ dict_table_t *purge_sys_t::close_and_reopen(table_id_t id, THD *thd,
|
||||
if (t.second.first == reinterpret_cast<dict_table_t*>(-1))
|
||||
{
|
||||
if (table)
|
||||
dict_table_close(table, false, thd, *mdl);
|
||||
dict_table_close(table, thd, *mdl);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user