Skip to content

Commit 70ad689

Browse files
author
Jan Lindström
committed
MDEV-8633: information_schema.index_statistics doesn't delete
item when drop table indexes or drop table; Problem was that table and index statistics is removed from persistent tables but not from memory cache. Added functions to remove table and index statistics from memory cache.
1 parent e24a183 commit 70ad689

File tree

6 files changed

+219
-5
lines changed

6 files changed

+219
-5
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
set global userstat=1;
2+
create table just_a_test(id int,first_name varchar(10),last_name varchar(10),address varchar(100),phone bigint,email varchar(30), state varchar(30));
3+
insert into just_a_test values(1,'fa','la','china_a',11111111,'fa_la@163.com','California'),
4+
(2,'fb','lb','china_b',22222222,'fb_lb@163.com','Arizona'),
5+
(3,'fc','lc','china_c',33333333,'fc_lc@163.com','California'),
6+
(4,'fd','ld','china_d',44444444,'fd_ld@163.com','Utah'),
7+
(5,'fe','le','china_e',55555555,'fe_le@163.com','Arizona');
8+
alter table just_a_test add primary key (id);
9+
alter table just_a_test add key IND_just_a_test_first_name_last_name(first_name,last_name);
10+
alter table just_a_test add key IND_just_a_test_state(state);
11+
select count(*) from just_a_test where first_name='fc' and last_name='lc';
12+
count(*)
13+
1
14+
select count(*) from just_a_test where state = 'California';
15+
count(*)
16+
2
17+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
18+
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
19+
test just_a_test IND_just_a_test_state 2
20+
test just_a_test IND_just_a_test_first_name_last_name 1
21+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
22+
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
23+
test just_a_test 18 5 5
24+
alter table just_a_test drop key IND_just_a_test_first_name_last_name;
25+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
26+
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
27+
test just_a_test IND_just_a_test_state 2
28+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
29+
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
30+
test just_a_test 23 5 5
31+
alter table just_a_test drop column state;
32+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
33+
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
34+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
35+
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
36+
test just_a_test 28 5 5
37+
drop table just_a_test;
38+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
39+
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
40+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
41+
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
42+
create table just_a_test(id int not null primary key,first_name varchar(10),last_name varchar(10),address varchar(100),phone bigint,email varchar(30), state varchar(30),key(first_name,last_name),key(state));
43+
insert into just_a_test values(1,'fa','la','china_a',11111111,'fa_la@163.com','California'),
44+
(2,'fb','lb','china_b',22222222,'fb_lb@163.com','Arizona'),
45+
(3,'fc','lc','china_c',33333333,'fc_lc@163.com','California'),
46+
(4,'fd','ld','china_d',44444444,'fd_ld@163.com','Utah'),
47+
(5,'fe','le','china_e',55555555,'fe_le@163.com','Arizona');
48+
select count(*) from just_a_test where first_name='fc' and last_name='lc';
49+
count(*)
50+
1
51+
select count(*) from just_a_test where state = 'California';
52+
count(*)
53+
2
54+
select count(*) from just_a_test where id between 2 and 4;
55+
count(*)
56+
3
57+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
58+
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
59+
test just_a_test first_name 1
60+
test just_a_test state 2
61+
test just_a_test PRIMARY 5
62+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
63+
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
64+
test just_a_test 8 5 15
65+
drop table just_a_test;
66+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
67+
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
68+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
69+
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
70+
set global userstat=0;

mysql-test/r/status_user.result

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,12 @@ handler_read_key
128128
set @@global.userstat=0;
129129
select * from information_schema.index_statistics;
130130
TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ
131-
test t1 PRIMARY 2
132131
select * from information_schema.table_statistics;
133132
TABLE_SCHEMA TABLE_NAME ROWS_READ ROWS_CHANGED ROWS_CHANGED_X_INDEXES
134-
test t1 6 13 13
135133
show table_statistics;
136134
Table_schema Table_name Rows_read Rows_changed Rows_changed_x_#indexes
137-
test t1 6 13 13
138135
show index_statistics;
139136
Table_schema Table_name Index_name Rows_read
140-
test t1 PRIMARY 2
141137
select TOTAL_CONNECTIONS, CONCURRENT_CONNECTIONS, ROWS_READ, ROWS_SENT, ROWS_DELETED, ROWS_INSERTED, ROWS_UPDATED, SELECT_COMMANDS, UPDATE_COMMANDS, OTHER_COMMANDS, COMMIT_TRANSACTIONS, ROLLBACK_TRANSACTIONS, DENIED_CONNECTIONS, LOST_CONNECTIONS, ACCESS_DENIED, EMPTY_QUERIES from information_schema.client_statistics;;
142138
TOTAL_CONNECTIONS 1
143139
CONCURRENT_CONNECTIONS 0
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#
2+
# MDEV-8633: information_schema.index_statistics doesn't delete item when drop table indexes or drop table;
3+
#
4+
set global userstat=1;
5+
create table just_a_test(id int,first_name varchar(10),last_name varchar(10),address varchar(100),phone bigint,email varchar(30), state varchar(30));
6+
insert into just_a_test values(1,'fa','la','china_a',11111111,'fa_la@163.com','California'),
7+
(2,'fb','lb','china_b',22222222,'fb_lb@163.com','Arizona'),
8+
(3,'fc','lc','china_c',33333333,'fc_lc@163.com','California'),
9+
(4,'fd','ld','china_d',44444444,'fd_ld@163.com','Utah'),
10+
(5,'fe','le','china_e',55555555,'fe_le@163.com','Arizona');
11+
alter table just_a_test add primary key (id);
12+
alter table just_a_test add key IND_just_a_test_first_name_last_name(first_name,last_name);
13+
alter table just_a_test add key IND_just_a_test_state(state);
14+
select count(*) from just_a_test where first_name='fc' and last_name='lc';
15+
select count(*) from just_a_test where state = 'California';
16+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
17+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
18+
alter table just_a_test drop key IND_just_a_test_first_name_last_name;
19+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
20+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
21+
alter table just_a_test drop column state;
22+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
23+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
24+
drop table just_a_test;
25+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
26+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
27+
#
28+
# Test direct drop table
29+
#
30+
create table just_a_test(id int not null primary key,first_name varchar(10),last_name varchar(10),address varchar(100),phone bigint,email varchar(30), state varchar(30),key(first_name,last_name),key(state));
31+
insert into just_a_test values(1,'fa','la','china_a',11111111,'fa_la@163.com','California'),
32+
(2,'fb','lb','china_b',22222222,'fb_lb@163.com','Arizona'),
33+
(3,'fc','lc','china_c',33333333,'fc_lc@163.com','California'),
34+
(4,'fd','ld','china_d',44444444,'fd_ld@163.com','Utah'),
35+
(5,'fe','le','china_e',55555555,'fe_le@163.com','Arizona');
36+
select count(*) from just_a_test where first_name='fc' and last_name='lc';
37+
select count(*) from just_a_test where state = 'California';
38+
select count(*) from just_a_test where id between 2 and 4;
39+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
40+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
41+
drop table just_a_test;
42+
select * from information_schema.index_statistics where table_schema='test' and table_name='just_a_test';
43+
select * from information_schema.table_statistics where table_schema='test' and table_name='just_a_test';
44+
set global userstat=0;

sql/sql_show.cc

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3460,6 +3460,100 @@ int fill_schema_table_stats(THD *thd, TABLE_LIST *tables, COND *cond)
34603460
DBUG_RETURN(0);
34613461
}
34623462

3463+
/* Remove all indexes for a given table from global index statistics */
3464+
3465+
static
3466+
int del_global_index_stats_for_table(THD *thd, uchar* cache_key, uint cache_key_length)
3467+
{
3468+
int res = 0;
3469+
DBUG_ENTER("del_global_index_stats_for_table");
3470+
3471+
mysql_mutex_lock(&LOCK_global_index_stats);
3472+
3473+
for (uint i= 0; i < global_index_stats.records;)
3474+
{
3475+
INDEX_STATS *index_stats =
3476+
(INDEX_STATS*) my_hash_element(&global_index_stats, i);
3477+
3478+
/* We search correct db\0table_name\0 string */
3479+
if (index_stats &&
3480+
index_stats->index_name_length >= cache_key_length &&
3481+
!memcmp(index_stats->index, cache_key, cache_key_length))
3482+
{
3483+
res= my_hash_delete(&global_index_stats, (uchar*)index_stats);
3484+
/*
3485+
In our HASH implementation on deletion one elements
3486+
is moved into a place where a deleted element was,
3487+
and the last element is moved into the empty space.
3488+
Thus we need to re-examine the current element, but
3489+
we don't have to restart the search from the beginning.
3490+
*/
3491+
}
3492+
else
3493+
i++;
3494+
}
3495+
3496+
mysql_mutex_unlock(&LOCK_global_index_stats);
3497+
DBUG_RETURN(res);
3498+
}
3499+
3500+
/* Remove a table from global table statistics */
3501+
3502+
int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table)
3503+
{
3504+
TABLE_STATS *table_stats;
3505+
int res = 0;
3506+
uchar *cache_key;
3507+
uint cache_key_length;
3508+
DBUG_ENTER("del_global_table_stat");
3509+
3510+
cache_key_length= db->length + 1 + table->length + 1;
3511+
3512+
if(!(cache_key= (uchar *)my_malloc(cache_key_length,
3513+
MYF(MY_WME | MY_ZEROFILL))))
3514+
{
3515+
/* Out of memory error already given */
3516+
res = 1;
3517+
goto end;
3518+
}
3519+
3520+
memcpy(cache_key, db->str, db->length);
3521+
memcpy(cache_key + db->length + 1, table->str, table->length);
3522+
3523+
res= del_global_index_stats_for_table(thd, cache_key, cache_key_length);
3524+
3525+
mysql_mutex_lock(&LOCK_global_table_stats);
3526+
3527+
if((table_stats= (TABLE_STATS*) my_hash_search(&global_table_stats,
3528+
cache_key,
3529+
cache_key_length)))
3530+
res= my_hash_delete(&global_table_stats, (uchar*)table_stats);
3531+
3532+
my_free(cache_key);
3533+
mysql_mutex_unlock(&LOCK_global_table_stats);
3534+
3535+
end:
3536+
DBUG_RETURN(res);
3537+
}
3538+
3539+
/* Remove a index from global index statistics */
3540+
3541+
int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info)
3542+
{
3543+
INDEX_STATS *index_stats;
3544+
uint key_length= table->s->table_cache_key.length + key_info->name_length + 1;
3545+
int res = 0;
3546+
DBUG_ENTER("del_global_index_stat");
3547+
mysql_mutex_lock(&LOCK_global_index_stats);
3548+
3549+
if((index_stats= (INDEX_STATS*) my_hash_search(&global_index_stats,
3550+
key_info->cache_name,
3551+
key_length)))
3552+
res= my_hash_delete(&global_index_stats, (uchar*)index_stats);
3553+
3554+
mysql_mutex_unlock(&LOCK_global_index_stats);
3555+
DBUG_RETURN(res);
3556+
}
34633557

34643558
/* Fill information schema table with index statistics */
34653559

sql/sql_show.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ void view_store_options(THD *thd, TABLE_LIST *table, String *buff);
113113
void init_fill_schema_files_row(TABLE* table);
114114
bool schema_table_store_record(THD *thd, TABLE *table);
115115
void initialize_information_schema_acl();
116-
116+
int del_global_index_stat(THD *thd, TABLE* tab, KEY* key_info);
117+
int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table);
117118
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
118119
ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
119120
int make_schema_select(THD *thd, SELECT_LEX *sel,

sql/sql_statistics.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "sql_statistics.h"
3030
#include "opt_range.h"
3131
#include "my_atomic.h"
32+
#include "sql_show.h"
3233

3334
/*
3435
The system variable 'use_stat_tables' can take one of the
@@ -3193,6 +3194,10 @@ int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab)
31933194
rc= 1;
31943195
}
31953196

3197+
err= del_global_table_stat(thd, db, tab);
3198+
if (err & !rc)
3199+
rc= 1;
3200+
31963201
thd->restore_stmt_binlog_format(save_binlog_format);
31973202

31983203
close_system_tables(thd, &open_tables_backup);
@@ -3339,6 +3344,10 @@ int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info,
33393344
}
33403345
}
33413346

3347+
err= del_global_index_stat(thd, tab, key_info);
3348+
if (err && !rc)
3349+
rc= 1;
3350+
33423351
thd->restore_stmt_binlog_format(save_binlog_format);
33433352

33443353
close_system_tables(thd, &open_tables_backup);

0 commit comments

Comments
 (0)