From 5d20f7b346cdfea327734d741510d370fa4c0782 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 7 Aug 2013 17:08:51 -0700 Subject: [PATCH] Added missing tests for innodb persistent statistics (from mysql-5.6.10) Made sure that innodb tables for persistent statistics would not considered by the server as system tables. --- .../suite/innodb/include/innodb_stats.inc | 26 + mysql-test/suite/innodb/r/innodb_stats.result | 522 ++++++++++++++++++ .../r/innodb_stats_create_on_corrupted.result | 20 + .../innodb/r/innodb_stats_create_table.result | 35 ++ .../innodb/r/innodb_stats_drop_locked.result | 45 ++ .../suite/innodb/r/innodb_stats_fetch.result | 145 +++++ .../r/innodb_stats_fetch_corrupted.result | 31 ++ .../r/innodb_stats_fetch_nonexistent.result | 27 + .../innodb/r/innodb_stats_rename_table.result | 50 ++ ...innodb_stats_rename_table_if_exists.result | 80 +++ mysql-test/suite/innodb/t/innodb_stats.test | 61 ++ .../t/innodb_stats_create_on_corrupted.test | 36 ++ .../innodb/t/innodb_stats_create_table.test | 66 +++ .../innodb/t/innodb_stats_drop_locked.test | 61 ++ .../suite/innodb/t/innodb_stats_fetch.test | 79 +++ .../t/innodb_stats_fetch_corrupted.test | 45 ++ .../t/innodb_stats_fetch_nonexistent.test | 36 ++ .../innodb/t/innodb_stats_rename_table.test | 42 ++ .../innodb_stats_rename_table_if_exists.test | 58 ++ sql/table.cc | 16 +- 20 files changed, 1475 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/innodb/include/innodb_stats.inc create mode 100644 mysql-test/suite/innodb/r/innodb_stats.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_create_on_corrupted.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_create_table.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_drop_locked.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_fetch.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_fetch_corrupted.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_fetch_nonexistent.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_rename_table.result create mode 100644 mysql-test/suite/innodb/r/innodb_stats_rename_table_if_exists.result create mode 100644 mysql-test/suite/innodb/t/innodb_stats.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_create_on_corrupted.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_create_table.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_drop_locked.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_fetch.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_fetch_nonexistent.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_rename_table.test create mode 100644 mysql-test/suite/innodb/t/innodb_stats_rename_table_if_exists.test diff --git a/mysql-test/suite/innodb/include/innodb_stats.inc b/mysql-test/suite/innodb/include/innodb_stats.inc new file mode 100644 index 00000000000..c765521d4a7 --- /dev/null +++ b/mysql-test/suite/innodb/include/innodb_stats.inc @@ -0,0 +1,26 @@ +TRUNCATE TABLE test_innodb_stats; + +-- eval $insert + +ANALYZE TABLE test_innodb_stats; + +query_vertical SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; + +# provoke reading from persistent storage upon next table access (the SELECT +# from information_schema.statistics below) +FLUSH TABLE test_innodb_stats; + +# see what we are going to read +query_vertical SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; diff --git a/mysql-test/suite/innodb/r/innodb_stats.result b/mysql-test/suite/innodb/r/innodb_stats.result new file mode 100644 index 00000000000..d2c3bd0127e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats.result @@ -0,0 +1,522 @@ +TRUNCATE TABLE test_innodb_stats; +SELECT 'dummy INSERT, the table should be empty'; +dummy INSERT, the table should be empty +dummy INSERT, the table should be empty +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 0 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 0 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 0 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 1 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 1 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 1 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (1); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 1 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 2 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 2 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (1), (1); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 1 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 3 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 3 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 1 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 10 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 2 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (2); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 2 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 2 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 2 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (1), (2); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 2 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 3 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 3 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (2), (3); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 3 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 3 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 3 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (1), (2), (3), (3); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 3 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 5 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 5 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT +TRUNCATE TABLE test_innodb_stats; +INSERT INTO test_innodb_stats (a) VALUES (1), (2), (3), (4), (5), (1), (2), (3), (4), (5); +ANALYZE TABLE test_innodb_stats; +Table Op Msg_type Msg_text +test.test_innodb_stats analyze status OK +SELECT +stat_name, +stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE +database_name = DATABASE() AND +table_name = 'test_innodb_stats' AND +index_name = 'a_key' AND +stat_name IN ('n_diff_pfx01', 'n_diff_pfx02', 'n_leaf_pages', 'size') +ORDER BY stat_name; +stat_name n_diff_pfx01 +stat_value 5 +sample_size 1 +stat_description a +stat_name n_diff_pfx02 +stat_value 10 +sample_size 1 +stat_description a,DB_ROW_ID +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +FLUSH TABLE test_innodb_stats; +SELECT * FROM information_schema.statistics +WHERE table_name = 'test_innodb_stats'; +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME test_innodb_stats +NON_UNIQUE 1 +INDEX_SCHEMA test +INDEX_NAME a_key +SEQ_IN_INDEX 1 +COLUMN_NAME a +COLLATION A +CARDINALITY 10 +SUB_PART NULL +PACKED NULL +NULLABLE YES +INDEX_TYPE BTREE +COMMENT +INDEX_COMMENT diff --git a/mysql-test/suite/innodb/r/innodb_stats_create_on_corrupted.result b/mysql-test/suite/innodb/r/innodb_stats_create_on_corrupted.result new file mode 100644 index 00000000000..47c714bb0a6 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_create_on_corrupted.result @@ -0,0 +1,20 @@ +call mtr.add_suppression("InnoDB: Error: Table \"mysql\".\"innodb_index_stats\" not found"); +call mtr.add_suppression("InnoDB: Error: Fetch of persistent statistics requested for table"); +ALTER TABLE mysql.innodb_index_stats RENAME TO mysql.innodb_index_stats_; +CREATE TABLE test_ps_create_on_corrupted +(a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; +SELECT seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_create_on_corrupted' +ORDER BY index_name, seq_in_index; +seq_in_index 1 +column_name a +cardinality 0 +SELECT table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_create_on_corrupted'; +table_rows 0 +avg_row_length 0 +max_data_length 0 +index_length 0 +ALTER TABLE mysql.innodb_index_stats_ RENAME TO mysql.innodb_index_stats; +DROP TABLE test_ps_create_on_corrupted; diff --git a/mysql-test/suite/innodb/r/innodb_stats_create_table.result b/mysql-test/suite/innodb/r/innodb_stats_create_table.result new file mode 100644 index 00000000000..c37c4671fd1 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_create_table.result @@ -0,0 +1,35 @@ +set @save_innodb_stats_persistent= @@innodb_stats_persistent; +set global innodb_stats_persistent=default; +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; +COUNT(*) 0 +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=0; +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; +COUNT(*) 0 +DROP TABLE test_ps_create_table; +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB; +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; +COUNT(*) 1 +DROP TABLE test_ps_create_table; +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=default; +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; +COUNT(*) 1 +DROP TABLE test_ps_create_table; +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; +COUNT(*) 1 +DROP TABLE test_ps_create_table; +set global innodb_stats_persistent= @save_innodb_stats_persistent; diff --git a/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result b/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result new file mode 100644 index 00000000000..13cc45e0ef9 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result @@ -0,0 +1,45 @@ +Table Op Msg_type Msg_text +test.innodb_stats_drop_locked analyze status OK +SET autocommit=0; +SELECT table_name FROM mysql.innodb_table_stats +WHERE table_name='innodb_stats_drop_locked' +FOR UPDATE; +table_name +innodb_stats_drop_locked +SELECT table_name FROM mysql.innodb_index_stats +WHERE table_name='innodb_stats_drop_locked' +FOR UPDATE; +table_name +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +ALTER TABLE innodb_stats_drop_locked DROP INDEX c_key; +Warnings: +Warning 1205 Unable to delete statistics for index c_key from mysql.innodb_index_stats because the rows are locked: Lock wait timeout. They can be deleted later using DELETE FROM mysql.innodb_index_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked' AND index_name = 'c_key'; +SHOW CREATE TABLE innodb_stats_drop_locked; +Table Create Table +innodb_stats_drop_locked CREATE TABLE `innodb_stats_drop_locked` ( + `c` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=1 +DROP TABLE innodb_stats_drop_locked; +SHOW TABLES; +Tables_in_test +COMMIT; +SELECT table_name FROM mysql.innodb_table_stats +WHERE table_name='innodb_stats_drop_locked'; +table_name +innodb_stats_drop_locked +SELECT table_name FROM mysql.innodb_index_stats +WHERE table_name='innodb_stats_drop_locked'; +table_name +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked +innodb_stats_drop_locked diff --git a/mysql-test/suite/innodb/r/innodb_stats_fetch.result b/mysql-test/suite/innodb/r/innodb_stats_fetch.result new file mode 100644 index 00000000000..b348e41f1d9 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_fetch.result @@ -0,0 +1,145 @@ +CREATE TABLE test_ps_fetch +(a INT, b INT, c INT, d INT, PRIMARY KEY (a, b), INDEX idx (c, d)) +ENGINE=INNODB STATS_PERSISTENT=1; +ANALYZE TABLE test_ps_fetch; +Table test.test_ps_fetch +Op analyze +Msg_type status +Msg_text OK +SELECT n_rows, clustered_index_size, sum_of_other_index_sizes +FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch'; +n_rows 0 +clustered_index_size 1 +sum_of_other_index_sizes 1 +SELECT index_name, stat_name, stat_value, sample_size, stat_description +FROM mysql.innodb_index_stats WHERE table_name = 'test_ps_fetch' +ORDER BY index_name, stat_name; +index_name PRIMARY +stat_name n_diff_pfx01 +stat_value 0 +sample_size 1 +stat_description a +index_name PRIMARY +stat_name n_diff_pfx02 +stat_value 0 +sample_size 1 +stat_description a,b +index_name PRIMARY +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +index_name PRIMARY +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +index_name idx +stat_name n_diff_pfx01 +stat_value 0 +sample_size 1 +stat_description c +index_name idx +stat_name n_diff_pfx02 +stat_value 0 +sample_size 1 +stat_description c,d +index_name idx +stat_name n_diff_pfx03 +stat_value 0 +sample_size 1 +stat_description c,d,a +index_name idx +stat_name n_diff_pfx04 +stat_value 0 +sample_size 1 +stat_description c,d,a,b +index_name idx +stat_name n_leaf_pages +stat_value 1 +sample_size NULL +stat_description Number of leaf pages in the index +index_name idx +stat_name size +stat_value 1 +sample_size NULL +stat_description Number of pages in the index +SELECT index_name, seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_fetch' +ORDER BY index_name, seq_in_index; +index_name idx +seq_in_index 1 +column_name c +cardinality 0 +index_name idx +seq_in_index 2 +column_name d +cardinality 0 +index_name PRIMARY +seq_in_index 1 +column_name a +cardinality 0 +index_name PRIMARY +seq_in_index 2 +column_name b +cardinality 0 +SELECT +table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch'; +table_rows 0 +avg_row_length 0 +max_data_length 0 +index_length 16384 +UPDATE mysql.innodb_table_stats SET +n_rows = 1000, +clustered_index_size = 5 +WHERE +table_name = 'test_ps_fetch'; +UPDATE mysql.innodb_index_stats SET +stat_value = 20 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'PRIMARY' AND +stat_name = 'n_diff_pfx01'; +UPDATE mysql.innodb_index_stats SET +stat_value = 90 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'PRIMARY' AND +stat_name = 'n_diff_pfx02'; +UPDATE mysql.innodb_index_stats SET +stat_value = 3 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'idx' AND +stat_name = 'n_diff_pfx01'; +UPDATE mysql.innodb_index_stats SET +stat_value = 11 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'idx' AND +stat_name = 'n_diff_pfx02'; +FLUSH TABLE 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; +seq_in_index 1 +column_name c +cardinality 6 +seq_in_index 2 +column_name d +cardinality 22 +seq_in_index 1 +column_name a +cardinality 40 +seq_in_index 2 +column_name b +cardinality 200 +SELECT +table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch'; +table_rows 1000 +avg_row_length 81 +max_data_length 0 +index_length 16384 +DROP TABLE test_ps_fetch; diff --git a/mysql-test/suite/innodb/r/innodb_stats_fetch_corrupted.result b/mysql-test/suite/innodb/r/innodb_stats_fetch_corrupted.result new file mode 100644 index 00000000000..f6cce754527 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_fetch_corrupted.result @@ -0,0 +1,31 @@ +call mtr.add_suppression("InnoDB: Error: Table \"mysql\".\"innodb_index_stats\" not found"); +call mtr.add_suppression("InnoDB: Error: Fetch of persistent statistics requested for table"); +CREATE TABLE test_ps_fetch_corrupted +(a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; +ANALYZE TABLE test_ps_fetch_corrupted; +Table test.test_ps_fetch_corrupted +Op analyze +Msg_type status +Msg_text OK +SELECT n_rows, clustered_index_size, sum_of_other_index_sizes +FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_corrupted'; +n_rows 0 +clustered_index_size 1 +sum_of_other_index_sizes 0 +ALTER TABLE mysql.innodb_index_stats RENAME TO mysql.innodb_index_stats_; +FLUSH TABLE test_ps_fetch_corrupted; +SELECT seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_fetch_corrupted' +ORDER BY index_name, seq_in_index; +seq_in_index 1 +column_name a +cardinality 0 +SELECT table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch_corrupted'; +table_rows 0 +avg_row_length 0 +max_data_length 0 +index_length 0 +ALTER TABLE mysql.innodb_index_stats_ RENAME TO mysql.innodb_index_stats; +DROP TABLE test_ps_fetch_corrupted; diff --git a/mysql-test/suite/innodb/r/innodb_stats_fetch_nonexistent.result b/mysql-test/suite/innodb/r/innodb_stats_fetch_nonexistent.result new file mode 100644 index 00000000000..4d1b8817bf1 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_fetch_nonexistent.result @@ -0,0 +1,27 @@ +CREATE TABLE test_ps_fetch_nonexistent +(a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; +ANALYZE TABLE test_ps_fetch_nonexistent; +Table test.test_ps_fetch_nonexistent +Op analyze +Msg_type status +Msg_text OK +SELECT COUNT(*) +FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_nonexistent'; +COUNT(*) 1 +DELETE FROM mysql.innodb_index_stats WHERE table_name = 'test_ps_fetch_nonexistent'; +DELETE FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_nonexistent'; +FLUSH TABLE test_ps_fetch_nonexistent; +SELECT seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_fetch_nonexistent' +ORDER BY index_name, seq_in_index; +seq_in_index 1 +column_name a +cardinality 0 +SELECT table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch_nonexistent'; +table_rows 0 +avg_row_length 0 +max_data_length 0 +index_length 0 +DROP TABLE test_ps_fetch_nonexistent; diff --git a/mysql-test/suite/innodb/r/innodb_stats_rename_table.result b/mysql-test/suite/innodb/r/innodb_stats_rename_table.result new file mode 100644 index 00000000000..20d82dff9ba --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_rename_table.result @@ -0,0 +1,50 @@ +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); +CREATE TABLE stats_rename_old (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); +table_name stats_rename_old +n_rows 0 +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); +table_name stats_rename_old +index_name PRIMARY +stat_name n_diff_pfx01 +stat_value 0 +table_name stats_rename_old +index_name PRIMARY +stat_name n_leaf_pages +stat_value 1 +table_name stats_rename_old +index_name PRIMARY +stat_name size +stat_value 1 +RENAME TABLE stats_rename_old TO stats_rename_new; +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); +table_name stats_rename_new +n_rows 0 +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); +table_name stats_rename_new +index_name PRIMARY +stat_name n_diff_pfx01 +stat_value 0 +table_name stats_rename_new +index_name PRIMARY +stat_name n_leaf_pages +stat_value 1 +table_name stats_rename_new +index_name PRIMARY +stat_name size +stat_value 1 +DROP TABLE stats_rename_new; diff --git a/mysql-test/suite/innodb/r/innodb_stats_rename_table_if_exists.result b/mysql-test/suite/innodb/r/innodb_stats_rename_table_if_exists.result new file mode 100644 index 00000000000..5614b4ba490 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_stats_rename_table_if_exists.result @@ -0,0 +1,80 @@ +CREATE TABLE stats_rename1 (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; +INSERT INTO mysql.innodb_table_stats +SELECT +database_name, +'stats_rename2' AS table_name, +last_update, +123 AS n_rows, +clustered_index_size, +sum_of_other_index_sizes +FROM mysql.innodb_table_stats +WHERE table_name = 'stats_rename1'; +INSERT INTO mysql.innodb_index_stats +SELECT +database_name, +'stats_rename2' AS table_name, +index_name, +last_update, +stat_name, +567 AS stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE table_name = 'stats_rename1'; +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); +table_name stats_rename1 +n_rows 0 +table_name stats_rename2 +n_rows 123 +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); +table_name stats_rename1 +index_name PRIMARY +stat_name n_diff_pfx01 +stat_value 0 +table_name stats_rename1 +index_name PRIMARY +stat_name n_leaf_pages +stat_value 1 +table_name stats_rename1 +index_name PRIMARY +stat_name size +stat_value 1 +table_name stats_rename2 +index_name PRIMARY +stat_name n_diff_pfx01 +stat_value 567 +table_name stats_rename2 +index_name PRIMARY +stat_name n_leaf_pages +stat_value 567 +table_name stats_rename2 +index_name PRIMARY +stat_name size +stat_value 567 +RENAME TABLE stats_rename1 TO stats_rename2; +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); +table_name stats_rename2 +n_rows 0 +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); +table_name stats_rename2 +index_name PRIMARY +stat_name n_diff_pfx01 +stat_value 0 +table_name stats_rename2 +index_name PRIMARY +stat_name n_leaf_pages +stat_value 1 +table_name stats_rename2 +index_name PRIMARY +stat_name size +stat_value 1 +DROP TABLE stats_rename2; diff --git a/mysql-test/suite/innodb/t/innodb_stats.test b/mysql-test/suite/innodb/t/innodb_stats.test new file mode 100644 index 00000000000..b9f71f8fa6f --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats.test @@ -0,0 +1,61 @@ +# +# Test the persistent stats feature +# + +-- source include/have_innodb.inc + +-- disable_warnings +-- disable_query_log + +DROP TABLE IF EXISTS test_innodb_stats; + +CREATE TABLE test_innodb_stats ( + a INT, + KEY a_key (a) +) ENGINE=INNODB STATS_PERSISTENT=1; + +-- enable_warnings +-- enable_query_log + +# test empty table +-- let $insert = SELECT 'dummy INSERT, the table should be empty' +-- source suite/innodb/include/innodb_stats.inc + +# test table with 1 row +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 2 eq rows +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (1) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 3 eq rows +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (1), (1) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 10 eq rows +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 2 diff rows +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (2) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 2 diff rows, 3 rows in total +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (1), (2) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 3 diff rows +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (2), (3) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 3 diff rows, 5 rows in total +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (1), (2), (3), (3) +-- source suite/innodb/include/innodb_stats.inc + +# test table with 5 diff rows, 10 rows in total +-- let $insert = INSERT INTO test_innodb_stats (a) VALUES (1), (2), (3), (4), (5), (1), (2), (3), (4), (5) +-- source suite/innodb/include/innodb_stats.inc + +-- disable_query_log +DROP TABLE test_innodb_stats; diff --git a/mysql-test/suite/innodb/t/innodb_stats_create_on_corrupted.test b/mysql-test/suite/innodb/t/innodb_stats_create_on_corrupted.test new file mode 100644 index 00000000000..78c9334f800 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_create_on_corrupted.test @@ -0,0 +1,36 @@ +# +# Test creating a persistent stats table on nonexistent or corrupted +# persistent storage +# + +-- source include/have_innodb.inc +# Various sizes printed in this test depend on the page size and the +# functionality tested here is not related to the page size, so we only +# test with 16k page size. +-- source include/have_innodb_16k.inc + +call mtr.add_suppression("InnoDB: Error: Table \"mysql\".\"innodb_index_stats\" not found"); +call mtr.add_suppression("InnoDB: Error: Fetch of persistent statistics requested for table"); + +-- vertical_results + +# corrupt the persistent storage +ALTER TABLE mysql.innodb_index_stats RENAME TO mysql.innodb_index_stats_; + +CREATE TABLE test_ps_create_on_corrupted +(a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; + +# check the stats (should have been generated using the old transient stats +# method) +SELECT seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_create_on_corrupted' +ORDER BY index_name, seq_in_index; + +SELECT table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_create_on_corrupted'; + +# restore the persistent storage +ALTER TABLE mysql.innodb_index_stats_ RENAME TO mysql.innodb_index_stats; + +DROP TABLE test_ps_create_on_corrupted; diff --git a/mysql-test/suite/innodb/t/innodb_stats_create_table.test b/mysql-test/suite/innodb/t/innodb_stats_create_table.test new file mode 100644 index 00000000000..e7ae09bd19d --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_create_table.test @@ -0,0 +1,66 @@ +# +# Test CREATE TABLE ... STATS_PERSISTENT=0|1|default +# + +-- source include/have_innodb.inc + +set @save_innodb_stats_persistent= @@innodb_stats_persistent; + +set global innodb_stats_persistent=default; + +-- vertical_results + +# confirm that nothing is present before the test +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; + +## + +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=0; + +# nothing should be present +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; + +DROP TABLE test_ps_create_table; + +## + +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB; + +# 1 row should be present if the default of --innodb-stats-persistent is 1 +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; + +DROP TABLE test_ps_create_table; + +## + +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=default; + +# 1 row should be present if the default of --innodb-stats-persistent is 1 +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; + +DROP TABLE test_ps_create_table; + +## + +CREATE TABLE test_ps_create_table (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; + +# 1 row should be present +SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE +database_name = 'test' AND +table_name = 'test_ps_create_table'; + +DROP TABLE test_ps_create_table; + +set global innodb_stats_persistent= @save_innodb_stats_persistent; diff --git a/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test b/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test new file mode 100644 index 00000000000..26367b8e6ae --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test @@ -0,0 +1,61 @@ +# +# Test the persistent stats feature when DROPping a table or an +# index when the corresponding rows in the stats tables are locked +# + +-- source include/have_innodb.inc + +-- disable_warnings +-- disable_query_log + +DROP TABLE IF EXISTS innodb_stats_drop_locked; + +CREATE TABLE innodb_stats_drop_locked (c INT, KEY c_key (c)) +ENGINE=INNODB STATS_PERSISTENT=1; + +ANALYZE TABLE innodb_stats_drop_locked; + +-- enable_warnings +-- enable_query_log + +SET autocommit=0; + +SELECT table_name FROM mysql.innodb_table_stats +WHERE table_name='innodb_stats_drop_locked' +FOR UPDATE; + +SELECT table_name FROM mysql.innodb_index_stats +WHERE table_name='innodb_stats_drop_locked' +FOR UPDATE; + +-- connect (con1,localhost,root,,) + +-- connection con1 + +ALTER TABLE innodb_stats_drop_locked DROP INDEX c_key; + +# the index should be gone +SHOW CREATE TABLE innodb_stats_drop_locked; + +DROP TABLE innodb_stats_drop_locked; + +# the table should be gone +SHOW TABLES; + +-- connection default + +-- disconnect con1 + +COMMIT; + +# the stats should be there + +SELECT table_name FROM mysql.innodb_table_stats +WHERE table_name='innodb_stats_drop_locked'; + +SELECT table_name FROM mysql.innodb_index_stats +WHERE table_name='innodb_stats_drop_locked'; + +--disable_query_log +call mtr.add_suppression("Unable to delete statistics for table test.innodb_stats_drop_locked: Lock wait timeout. They can be deleted later using DELETE FROM mysql.innodb_index_stats WHERE database_name"); +--enable_query_log diff --git a/mysql-test/suite/innodb/t/innodb_stats_fetch.test b/mysql-test/suite/innodb/t/innodb_stats_fetch.test new file mode 100644 index 00000000000..8544509ccad --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_fetch.test @@ -0,0 +1,79 @@ +# +# Test fetching from stats tables after manual update (ie FLUSH TABLE +# can be used to forcibly (re)fetch the stats from disk) +# + +-- source include/have_innodb.inc +# Various sizes printed in this test depend on the page size and the +# functionality tested here is not related to the page size, so we only +# test with 16k page size. +-- source include/have_innodb_16k.inc + +-- vertical_results + +CREATE TABLE test_ps_fetch +(a INT, b INT, c INT, d INT, PRIMARY KEY (a, b), INDEX idx (c, d)) +ENGINE=INNODB STATS_PERSISTENT=1; + +ANALYZE TABLE test_ps_fetch; + +SELECT n_rows, clustered_index_size, sum_of_other_index_sizes +FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch'; + +SELECT index_name, stat_name, stat_value, sample_size, stat_description +FROM mysql.innodb_index_stats WHERE table_name = 'test_ps_fetch' +ORDER BY index_name, stat_name; + +SELECT index_name, seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_fetch' +ORDER BY index_name, seq_in_index; + +SELECT +table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch'; + +UPDATE mysql.innodb_table_stats SET +n_rows = 1000, +clustered_index_size = 5 +WHERE +table_name = 'test_ps_fetch'; + +UPDATE mysql.innodb_index_stats SET +stat_value = 20 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'PRIMARY' AND +stat_name = 'n_diff_pfx01'; + +UPDATE mysql.innodb_index_stats SET +stat_value = 90 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'PRIMARY' AND +stat_name = 'n_diff_pfx02'; + +UPDATE mysql.innodb_index_stats SET +stat_value = 3 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'idx' AND +stat_name = 'n_diff_pfx01'; + +UPDATE mysql.innodb_index_stats SET +stat_value = 11 +WHERE +table_name = 'test_ps_fetch' AND +index_name = 'idx' AND +stat_name = 'n_diff_pfx02'; + +FLUSH TABLE 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; + +SELECT +table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch'; + +DROP TABLE test_ps_fetch; diff --git a/mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test b/mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test new file mode 100644 index 00000000000..4a3f7527c09 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_fetch_corrupted.test @@ -0,0 +1,45 @@ +# +# Test fetching from stats tables that are corrupted +# + +-- source include/have_innodb.inc +# Various sizes printed in this test depend on the page size and the +# functionality tested here is not related to the page size, so we only +# test with 16k page size. +-- source include/have_innodb_16k.inc + +call mtr.add_suppression("InnoDB: Error: Table \"mysql\".\"innodb_index_stats\" not found"); +call mtr.add_suppression("InnoDB: Error: Fetch of persistent statistics requested for table"); + +-- vertical_results + +CREATE TABLE test_ps_fetch_corrupted +(a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; + +# write stats to mysql.innodb_table_stats +ANALYZE TABLE test_ps_fetch_corrupted; + +# check that indeed stats were written by ANALYZE above +SELECT n_rows, clustered_index_size, sum_of_other_index_sizes +FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_corrupted'; + +# corrupt the persistent storage +ALTER TABLE mysql.innodb_index_stats RENAME TO mysql.innodb_index_stats_; + +# reopen the table, this will attept to read from the persistent storage +FLUSH TABLE test_ps_fetch_corrupted; + +# check the stats (should have been generated using the old transient stats +# method) +SELECT seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_fetch_corrupted' +ORDER BY index_name, seq_in_index; + +SELECT table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch_corrupted'; + +# restore the persistent storage +ALTER TABLE mysql.innodb_index_stats_ RENAME TO mysql.innodb_index_stats; + +DROP TABLE test_ps_fetch_corrupted; diff --git a/mysql-test/suite/innodb/t/innodb_stats_fetch_nonexistent.test b/mysql-test/suite/innodb/t/innodb_stats_fetch_nonexistent.test new file mode 100644 index 00000000000..6c7365c52d1 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_fetch_nonexistent.test @@ -0,0 +1,36 @@ +# +# Test fetching from stats tables while there are no stats +# + +-- source include/have_innodb.inc + +-- vertical_results + +CREATE TABLE test_ps_fetch_nonexistent +(a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; + +# write stats to mysql.innodb_table_stats +ANALYZE TABLE test_ps_fetch_nonexistent; + +# check that indeed stats were written by ANALYZE above +SELECT COUNT(*) +FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_nonexistent'; + +# delete the stats +DELETE FROM mysql.innodb_index_stats WHERE table_name = 'test_ps_fetch_nonexistent'; +DELETE FROM mysql.innodb_table_stats WHERE table_name = 'test_ps_fetch_nonexistent'; + +# reopen the table, this will attept to read the stats +FLUSH TABLE test_ps_fetch_nonexistent; + +# check the stats (should have been generated using the old transient stats +# method) +SELECT seq_in_index, column_name, cardinality +FROM information_schema.statistics WHERE table_name = 'test_ps_fetch_nonexistent' +ORDER BY index_name, seq_in_index; + +SELECT table_rows, avg_row_length, max_data_length, index_length +FROM information_schema.tables WHERE table_name = 'test_ps_fetch_nonexistent'; + +DROP TABLE test_ps_fetch_nonexistent; diff --git a/mysql-test/suite/innodb/t/innodb_stats_rename_table.test b/mysql-test/suite/innodb/t/innodb_stats_rename_table.test new file mode 100644 index 00000000000..5c1fe0f2089 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_rename_table.test @@ -0,0 +1,42 @@ +# +# Test that RENAME TABLE renames the entries in +# mysql.innodb_table_stats and mysql.innodb_index_stats +# + +-- source include/have_innodb.inc + +-- vertical_results + +# confirm that nothing is present before the test +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); + +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); + +CREATE TABLE stats_rename_old (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; + +# confirm that CREATE inserted a zeroed entries +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); + +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); + +RENAME TABLE stats_rename_old TO stats_rename_new; + +# confirm that rows were updated correspondingly +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); + +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename_old', 'stats_rename_new'); + +DROP TABLE stats_rename_new; diff --git a/mysql-test/suite/innodb/t/innodb_stats_rename_table_if_exists.test b/mysql-test/suite/innodb/t/innodb_stats_rename_table_if_exists.test new file mode 100644 index 00000000000..e5b5d1814c0 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_stats_rename_table_if_exists.test @@ -0,0 +1,58 @@ +# +# Test what happens during RENAME TABLE if there are already rows in the stats +# tables for the new table. This cannot happen normally, one have to insert +# manually like what we do here. +# +# The RENAME should succeed and existent rows should be overwritten. +# + +-- source include/have_innodb.inc + +-- vertical_results + +CREATE TABLE stats_rename1 (a INT, PRIMARY KEY (a)) +ENGINE=INNODB STATS_PERSISTENT=1; + +INSERT INTO mysql.innodb_table_stats +SELECT +database_name, +'stats_rename2' AS table_name, +last_update, +123 AS n_rows, +clustered_index_size, +sum_of_other_index_sizes +FROM mysql.innodb_table_stats +WHERE table_name = 'stats_rename1'; + +INSERT INTO mysql.innodb_index_stats +SELECT +database_name, +'stats_rename2' AS table_name, +index_name, +last_update, +stat_name, +567 AS stat_value, +sample_size, +stat_description +FROM mysql.innodb_index_stats +WHERE table_name = 'stats_rename1'; + +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); + +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); + +RENAME TABLE stats_rename1 TO stats_rename2; + +SELECT table_name, n_rows +FROM mysql.innodb_table_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); + +SELECT table_name, index_name, stat_name, stat_value +FROM mysql.innodb_index_stats +WHERE table_name IN ('stats_rename1', 'stats_rename2'); + +DROP TABLE stats_rename2; diff --git a/sql/table.cc b/sql/table.cc index 26bbb5d046c..27a8fbee9a4 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -562,12 +562,16 @@ inline bool is_system_table_name(const char *name, uint length) my_tolower(ci, name[2]) == 'm' && my_tolower(ci, name[3]) == 'e') || - /* one of mysql.*_stat tables */ - (my_tolower(ci, name[length-5]) == 's' && - my_tolower(ci, name[length-4]) == 't' && - my_tolower(ci, name[length-3]) == 'a' && - my_tolower(ci, name[length-2]) == 't' && - my_tolower(ci, name[length-1]) == 's') || + /* one of mysql.*_stat tables, but not mysql.innodb* tables*/ + ((my_tolower(ci, name[length-5]) == 's' && + my_tolower(ci, name[length-4]) == 't' && + my_tolower(ci, name[length-3]) == 'a' && + my_tolower(ci, name[length-2]) == 't' && + my_tolower(ci, name[length-1]) == 's') && + !(my_tolower(ci, name[0]) == 'i' && + my_tolower(ci, name[1]) == 'n' && + my_tolower(ci, name[2]) == 'n' && + my_tolower(ci, name[3]) == 'o')) || /* mysql.event table */ (my_tolower(ci, name[0]) == 'e' &&