Commit 47fae7f0 authored by Igor Babaev's avatar Igor Babaev

Added procedures to delete records by keys from statistical tables.

Now when a table is dropped the statistics on the table is removed 
from the statistical tables. If the table is altered in such a way
that a column is dropped or the type of the column is changed then
statistics on the column is removed from the table column_stat.
It also triggers removal of the statistics on the indexes who use
this column as its component.

Added procedures that changes the names of the tables or columns
in the statistical tables for. 
These procedures are used when tables/columns are renamed.

Also partly re-factored the code that introduced the persistent
statistical tables.

Added test cases into statistics.test to cover the new code.
parent 4a6a0830
This diff is collapsed.
......@@ -107,7 +107,7 @@ Handler_mrr_key_refills 0
Handler_mrr_rowid_refills 0
Handler_prepare 18
Handler_read_first 0
Handler_read_key 3
Handler_read_key 9
Handler_read_last 0
Handler_read_next 0
Handler_read_prev 0
......@@ -123,7 +123,7 @@ Handler_update 5
Handler_write 7
select variable_value - @global_read_key as "handler_read_key" from information_schema.global_status where variable_name="handler_read_key";
handler_read_key
3
9
set @@global.userstat=0;
select * from information_schema.index_statistics;
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
......
......@@ -17,6 +17,7 @@ substring(object_name, locate("no_index_tab", object_name)) as short_name
from performance_schema.events_waits_history_long
where operation not like "tell"
and event_name like "wait/io/file/myisam/%"
having short_name <> ""
order by thread_id, event_id;
event_name short_source operation number_of_bytes short_name
wait/io/file/myisam/kfile mi_create.c: create NULL no_index_tab.MYI
......
......@@ -46,6 +46,7 @@ select event_name,
from performance_schema.events_waits_history_long
where operation not like "tell"
and event_name like "wait/io/file/myisam/%"
having short_name <> ""
order by thread_id, event_id;
# In case of failures, this will tell if file io are lost.
......
......@@ -20,10 +20,10 @@ CREATE TABLE t1 (
e double,
f bit(3),
INDEX idx1 (b, e),
INDEX idx2(c, d),
INDEX idx2 (c, d),
INDEX idx3 (d),
INDEX idx4 (e, b, d)
);
) ENGINE= MYISAM;
INSERT INTO t1 VALUES
(0, NULL, NULL, NULL, NULL, NULL),
......@@ -165,6 +165,180 @@ SELECT
WHERE t1.e IS NOT NULL AND t1.b IS NOT NULL AND t1.d IS NOT NULL)
AS 'ARITY 3';
CREATE TABLE t3 (
a int NOT NULL PRIMARY KEY,
b varchar(32),
c char(16),
INDEX idx (c)
) ENGINE=MYISAM;
INSERT INTO t3 VALUES
(0, NULL, NULL),
(7, 'xxxxxxxxxxxxxxxxxxxxxxxxxx', 'dddddddd'),
(17, 'vvvvvvvvvvvvv', 'aaaa'),
(1, 'vvvvvvvvvvvvv', NULL),
(12, 'wwwwwwwwwwwwwwwwwwwwwwwwwwww', 'dddddddd'),
(23, 'vvvvvvvvvvvvv', 'dddddddd'),
(8, 'vvvvvvvvvvvvv', 'aaaa'),
(22, 'xxxxxxxxxxxxxxxxxxxxxxxxxx', 'aaaa'),
(31, 'wwwwwwwwwwwwwwwwwwwwwwwwwwww', 'aaaa'),
(10, NULL, 'aaaa'),
(5, 'wwwwwwwwwwwwwwwwwwwwwwwwwwww', 'dddddddd'),
(15, 'vvvvvvvvvvvvv', 'ccccccccc'),
(30, NULL, 'bbbbbb'),
(38, 'zzzzzzzzzzzzzzzzzz', 'bbbbbb'),
(18, 'zzzzzzzzzzzzzzzzzz', 'ccccccccc'),
(9, 'yyy', 'bbbbbb'),
(29, 'vvvvvvvvvvvvv', 'dddddddd');
ANALYZE TABLE t3;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE t1 RENAME TO s1;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
RENAME TABLE s1 TO t1;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
DROP TABLE t3;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
CREATE TEMPORARY TABLE t0 (
a int NOT NULL PRIMARY KEY,
b varchar(32)
);
INSERT INTO t0 SELECT a,b FROM t1;
ALTER TABLE t1 CHANGE COLUMN b x varchar(32),
CHANGE COLUMN e y double;
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
ALTER TABLE t1 CHANGE COLUMN x b varchar(32),
CHANGE COLUMN y e double;
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
ALTER TABLE t1 RENAME TO s1, CHANGE COLUMN b x varchar(32);
SHOW CREATE TABLE s1;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE s1 RENAME TO t1, CHANGE COLUMN x b varchar(32);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE t1 CHANGE COLUMN b x varchar(30);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE t1 CHANGE COLUMN x b varchar(32);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(b) INDEXES(idx1, idx4);
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval
SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/save_column_stat'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n'
FROM mysql.column_stat WHERE column_name='b';
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval
SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/save_index_stat'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n'
FROM mysql.index_stat WHERE index_name IN ('idx1', 'idx4');
ALTER TABLE t1 CHANGE COLUMN b x varchar(30);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE t1 CHANGE COLUMN x b varchar(32);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval
LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/save_column_stat'
INTO TABLE mysql.column_stat
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval
LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/save_index_stat'
INTO TABLE mysql.index_stat
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
remove_file $MYSQLTEST_VARDIR/tmp/save_column_stat;
remove_file $MYSQLTEST_VARDIR/tmp/save_index_stat;
ALTER TABLE t1 DROP COLUMN b;
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
DROP INDEX idx2 ON t1;
SHOW CREATE TABLE t1;
SELECT * FROM mysql.index_stat;
DROP INDEX idx1 ON t1;
DROP INDEX idx4 ON t1;
SHOW CREATE TABLE t1;
ALTER TABLE t1 ADD COLUMN b varchar(32);
CREATE INDEX idx1 ON t1(b, e);
CREATE INDEX idx2 ON t1(c, d);
CREATE INDEX idx4 ON t1(e, b, d);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(b) INDEXES(idx1, idx2, idx4);
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
UPDATE t1 SET b=(SELECT b FROM t0 WHERE t0.a= t1.a);
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(b) INDEXES(idx1, idx2, idx4);
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE t1 DROP COLUMN b,
DROP INDEX idx1, DROP INDEX idx2, DROP INDEX idx4;
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ALTER TABLE t1 ADD COLUMN b varchar(32);
ALTER TABLE t1
ADD INDEX idx1 (b, e), ADD INDEX idx2 (c, d), ADD INDEX idx4 (e, b, d);
UPDATE t1 SET b=(SELECT b FROM t0 WHERE t0.a= t1.a);
SHOW CREATE TABLE t1;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(b) INDEXES(idx1, idx2, idx4);
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
DELETE FROM mysql.table_stat;
DELETE FROM mysql.column_stat;
DELETE FROM mysql.index_stat;
......@@ -297,7 +471,14 @@ SELECT UPPER(db_name), UPPER(table_name),
use test;
DROP DATABASE world;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
DROP DATABASE world_innodb;
SELECT * FROM mysql.table_stat;
SELECT * FROM mysql.column_stat;
SELECT * FROM mysql.index_stat;
DELETE FROM mysql.table_stat;
DELETE FROM mysql.column_stat;
......
......@@ -9649,7 +9649,8 @@ unlock_tables_n_open_system_tables_for_write(THD *thd,
DBUG_ENTER("unlock_tables_n_open_system_tables_for_write");
mysql_unlock_tables(thd, thd->lock);
if (thd->lock)
mysql_unlock_tables(thd, thd->lock);
thd->lock= 0;
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
......
......@@ -315,6 +315,13 @@ int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived);
int read_statistics_for_table(THD *thd, TABLE *table);
int collect_statistics_for_table(THD *thd, TABLE *table);
int update_statistics_for_table(THD *thd, TABLE *table);
int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab);
int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col);
int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info);
int rename_table_in_stat_tables(THD *thd, LEX_STRING *db, LEX_STRING *tab,
LEX_STRING *new_db, LEX_STRING *new_tab);
int rename_column_in_stat_tables(THD *thd, TABLE *tab, Field *col,
const char *new_name);
void set_statistics_for_table(THD *thd, TABLE *table);
extern "C" int simple_raw_key_cmp(void* arg, const void* key1,
......
......@@ -825,6 +825,17 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
lock_db_routines(thd, db))
goto exit;
if (!in_bootstrap)
{
for (table= tables; table; table= table->next_local)
{
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
/* mysql_ha_rm_tables() requires a non-null TABLE_LIST. */
if (tables)
mysql_ha_rm_tables(thd, tables);
......
......@@ -279,6 +279,12 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
ren_table->db, old_alias,
new_db, new_alias, 0)))
{
LEX_STRING db_name= { ren_table->db, ren_table->db_length };
LEX_STRING table_name= { ren_table->table_name,
ren_table->table_name_length };
LEX_STRING new_table= { (char *) new_alias, strlen(new_alias) };
(void) rename_table_in_stat_tables(thd, &db_name, &table_name,
&db_name, &new_table);
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
old_alias,
ren_table->table_name,
......
This diff is collapsed.
......@@ -1878,6 +1878,17 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
}
}
if (!in_bootstrap)
{
for (table= tables; table; table= table->next_local)
{
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
mysql_ha_rm_tables(thd, tables);
if (!drop_temporary)
......@@ -1888,6 +1899,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
MYSQL_OPEN_SKIP_TEMPORARY))
DBUG_RETURN(true);
for (table= tables; table; table= table->next_local)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
false);
}
......@@ -5084,6 +5096,21 @@ mysql_compare_tables(TABLE *table,
thd->calloc(sizeof(void*) * table->s->keys)) == NULL)
DBUG_RETURN(1);
tmp_new_field_it.init(tmp_alter_info.create_list);
for (i= 0, f_ptr= table->field, tmp_new_field= tmp_new_field_it++;
(field= *f_ptr);
i++, f_ptr++, tmp_new_field= tmp_new_field_it++)
{
if (field->is_equal(tmp_new_field) == IS_EQUAL_NO &&
table->s->tmp_table == NO_TMP_TABLE)
(void) delete_statistics_for_column(thd, table, field);
else if (my_strcasecmp(system_charset_info,
field->field_name,
tmp_new_field->field_name))
(void) rename_column_in_stat_tables(thd, table, field,
tmp_new_field->field_name);
}
/*
Use transformed info to evaluate possibility of in-place ALTER TABLE
but use the preserved field to persist modifications.
......@@ -5144,7 +5171,12 @@ mysql_compare_tables(TABLE *table,
if (my_strcasecmp(system_charset_info,
field->field_name,
tmp_new_field->field_name))
field->flags|= FIELD_IS_RENAMED;
{
field->flags|= FIELD_IS_RENAMED;
if (table->s->tmp_table == NO_TMP_TABLE)
rename_column_in_stat_tables(thd, table, field,
tmp_new_field->field_name);
}
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
if (!(tmp= field->is_equal(tmp_new_field)))
......@@ -5247,6 +5279,8 @@ mysql_compare_tables(TABLE *table,
field= table->field[key_part->fieldnr];
field->flags|= FIELD_IN_ADD_INDEX;
}
if (table->s->tmp_table == NO_TMP_TABLE)
(void) delete_statistics_for_index(thd, table, table_key);
DBUG_PRINT("info", ("index changed: '%s'", table_key->name));
}
/*end of for (; table_key < table_key_end;) */
......@@ -5504,6 +5538,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (drop)
{
if (table->s->tmp_table == NO_TMP_TABLE)
(void) delete_statistics_for_column(thd, table, field);
drop_it.remove();
/*
ALTER TABLE DROP COLUMN always changes table data even in cases
......@@ -5656,12 +5692,15 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (drop)
{
if (table->s->tmp_table == NO_TMP_TABLE)
(void) delete_statistics_for_index(thd, table, key_info);
drop_it.remove();
continue;
}
KEY_PART_INFO *key_part= key_info->key_part;
key_parts.empty();
bool delete_index_stat= FALSE;
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
if (!key_part->field)
......@@ -5684,7 +5723,10 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
break;
}
if (!cfield)
{
delete_index_stat= TRUE;
continue; // Field is removed
}
key_part_length= key_part->length;
if (cfield->field) // Not new field
{
......@@ -5726,6 +5768,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
strlen(cfield->field_name),
key_part_length));
}
if (delete_index_stat && table->s->tmp_table == NO_TMP_TABLE)
(void) delete_statistics_for_index(thd, table, key_info);
if (key_parts.elements)
{
KEY_CREATE_INFO key_create_info;
......@@ -5905,6 +5949,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
enum ha_extra_function extra_func= thd->locked_tables_mode
? HA_EXTRA_NOT_USED
: HA_EXTRA_FORCE_REOPEN;
LEX_STRING old_db_name= { table_list->db, table_list->db_length };
LEX_STRING old_table_name= { table_list->table_name,
table_list->table_name_length };
DBUG_ENTER("mysql_alter_table");
/*
......@@ -6209,6 +6256,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
else
{
*fn_ext(new_name)=0;
LEX_STRING new_db_name= { new_db, strlen(new_db) };
LEX_STRING new_table_name= { new_alias, strlen(new_alias) };
(void) rename_table_in_stat_tables(thd, &old_db_name, &old_table_name,
&new_db_name, &new_table_name);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
error= -1;
else if (Table_triggers_list::change_table_name(thd, db,
......@@ -6920,6 +6973,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
table is renamed and the SE is also changed, then an intermediate table
is created and the additional call will not take place.
*/
if (new_name != table_name || new_db != db)
{
LEX_STRING new_db_name= { new_db, strlen(new_db) };
LEX_STRING new_table_name= { new_name, strlen(new_name) };
(void) rename_table_in_stat_tables(thd, &old_db_name, &old_table_name,
&new_db_name, &new_table_name);
}
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
{
DBUG_ASSERT(new_db_type == old_db_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment