diff --git a/mysql-test/r/statistics.result b/mysql-test/r/statistics.result index e3f4d6bf564..ba0390f98db 100644 --- a/mysql-test/r/statistics.result +++ b/mysql-test/r/statistics.result @@ -499,14 +499,9 @@ test t1 f 1 5 0.2000 1.0000 6.4000 SELECT * FROM mysql.index_stats; db_name table_name index_name prefix_arity avg_frequency test t1 PRIMARY 1 1.0000 -test t1 idx1 1 6.4000 -test t1 idx1 2 1.6875 test t1 idx2 1 7.0000 test t1 idx2 2 2.3846 test t1 idx3 1 8.5000 -test t1 idx4 1 6.2000 -test t1 idx4 2 1.6875 -test t1 idx4 3 1.1304 ALTER TABLE t1 CHANGE COLUMN x b varchar(32); SHOW CREATE TABLE t1; Table Create Table @@ -590,14 +585,9 @@ test t1 f 1 5 0.2000 1.0000 6.4000 SELECT * FROM mysql.index_stats; db_name table_name index_name prefix_arity avg_frequency test t1 PRIMARY 1 1.0000 -test t1 idx4 3 1.1304 -test t1 idx4 2 1.6875 test t1 idx2 1 7.0000 test t1 idx2 2 2.3846 test t1 idx3 1 8.5000 -test t1 idx4 1 6.2000 -test t1 idx1 2 1.6875 -test t1 idx1 1 6.4000 ALTER TABLE t1 CHANGE COLUMN x b varchar(32); SHOW CREATE TABLE t1; Table Create Table @@ -943,6 +933,7 @@ test t1 idx4 3 1.1304 CREATE TABLE t2 LIKE t1; ALTER TABLE t2 ENGINE=InnoDB; INSERT INTO t2 SELECT * FROM t1; +set optimizer_switch='extended_keys=off'; ANALYZE TABLE t2; Table Op Msg_type Msg_text test.t2 analyze status OK @@ -987,6 +978,142 @@ test t2 idx4 3 1.1304 DELETE FROM mysql.table_stats; DELETE FROM mysql.column_stats; DELETE FROM mysql.index_stats; +set optimizer_switch='extended_keys=on'; +ANALYZE TABLE t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +SELECT * FROM mysql.table_stats; +db_name table_name cardinality +test t2 40 +SELECT * FROM mysql.column_stats ORDER BY column_name; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency +test t2 a 0 49 0.0000 4.0000 1.0000 +test t2 b vvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz 0.2000 17.1250 6.4000 +test t2 c aaaa dddddddd 0.1250 6.6571 7.0000 +test t2 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 +test t2 e 0.01 0.112 0.2250 8.0000 6.2000 +test t2 f 1 5 0.2000 1.0000 6.4000 +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 PRIMARY 1 1.0000 +test t2 idx1 1 6.4000 +test t2 idx1 2 1.6875 +test t2 idx1 3 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx2 3 1.0000 +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 1.6875 +test t2 idx4 3 1.1304 +test t2 idx4 4 1.0000 +ALTER TABLE t2 DROP PRIMARY KEY, DROP INDEX idx1; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx3 1 8.5000 +test t2 idx4 1 6.2000 +test t2 idx4 2 1.6875 +test t2 idx4 3 1.1304 +UPDATE t2 SET b=0 WHERE b IS NULL; +ALTER TABLE t2 ADD PRIMARY KEY (a,b); +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx3 1 8.5000 +test t2 idx4 1 6.2000 +test t2 idx4 2 1.6875 +test t2 idx4 3 1.1304 +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL; +Table Op Msg_type Msg_text +test.t2 analyze status OK +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 PRIMARY 1 1.0000 +test t2 PRIMARY 2 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx2 3 1.0000 +test t2 idx2 4 1.0000 +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx3 3 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 1.7222 +test t2 idx4 3 1.1154 +test t2 idx4 4 1.0000 +ALTER TABLE t2 CHANGE COLUMN b b varchar(30); +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx3 1 8.5000 +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL; +Table Op Msg_type Msg_text +test.t2 analyze status OK +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 PRIMARY 1 1.0000 +test t2 PRIMARY 2 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx2 3 1.0000 +test t2 idx2 4 1.0000 +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx3 3 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 1.7222 +test t2 idx4 3 1.1154 +test t2 idx4 4 1.0000 +ALTER TABLE t2 CHANGE COLUMN b b varchar(32); +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx3 1 8.5000 +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL; +Table Op Msg_type Msg_text +test.t2 analyze status OK +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 PRIMARY 1 1.0000 +test t2 PRIMARY 2 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx2 3 1.0000 +test t2 idx2 4 1.0000 +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx3 3 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 1.7222 +test t2 idx4 3 1.1154 +test t2 idx4 4 1.0000 +ALTER TABLE t2 DROP COLUMN b; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx3 1 8.5000 +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL; +Table Op Msg_type Msg_text +test.t2 analyze status OK +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; +db_name table_name index_name prefix_arity avg_frequency +test t2 PRIMARY 1 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx2 3 1.0000 +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 2.2308 +test t2 idx4 3 1.0000 +set optimizer_switch='extended_keys=off'; ALTER TABLE t1 DROP INDEX idx1, DROP INDEX idx4; @@ -994,11 +1121,34 @@ ALTER TABLE t1 MODIFY COLUMN b text, ADD INDEX idx1 (b(4), e), ADD INDEX idx4 (e, b(4), d); +SELECT * FROM mysql.column_stats; +db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency +test t2 a 0 49 0.0000 4.0000 1.0000 +test t2 c aaaa dddddddd 0.1250 6.6571 7.0000 +test t2 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 +test t2 e 0.01 0.112 0.2250 8.0000 6.2000 +test t2 f 1 5 0.2000 1.0000 6.4000 +SELECT * FROM mysql.index_stats; +db_name table_name index_name prefix_arity avg_frequency +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx2 3 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 +test t2 idx4 3 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 2.2308 +test t2 PRIMARY 1 1.0000 ANALYZE TABLE t1; Table Op Msg_type Msg_text test.t1 analyze status OK SELECT * FROM mysql.column_stats; db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency +test t2 a 0 49 0.0000 4.0000 1.0000 +test t2 c aaaa dddddddd 0.1250 6.6571 7.0000 +test t2 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 +test t2 e 0.01 0.112 0.2250 8.0000 6.2000 +test t2 f 1 5 0.2000 1.0000 6.4000 test t1 a 0 49 0.0000 4.0000 1.0000 test t1 c aaaa dddddddd 0.1250 6.6571 7.0000 test t1 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 @@ -1007,9 +1157,18 @@ test t1 f 1 5 0.2000 1.0000 6.4000 test t1 b NULL NULL 0.2000 17.1250 NULL SELECT * FROM mysql.index_stats; db_name table_name index_name prefix_arity avg_frequency -test t1 PRIMARY 1 1.0000 -test t1 idx3 1 8.5000 +test t2 idx3 1 8.5000 +test t2 idx3 2 1.0000 +test t2 idx2 3 1.0000 +test t2 idx2 1 7.0000 +test t2 idx2 2 2.3846 test t1 idx2 1 7.0000 +test t1 idx3 1 8.5000 +test t1 PRIMARY 1 1.0000 +test t2 idx4 3 1.0000 +test t2 idx4 1 6.2000 +test t2 idx4 2 2.2308 +test t2 PRIMARY 1 1.0000 test t1 idx2 2 2.3846 test t1 idx1 1 NULL test t1 idx1 2 NULL @@ -1057,28 +1216,6 @@ test t1 idx1 2 NULL test t1 idx4 1 6.2000 test t1 idx4 2 NULL test t1 idx4 3 NULL -SELECT * FROM mysql.table_stats; -db_name table_name cardinality -test t1 40 -SELECT * FROM mysql.column_stats; -db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency -test t1 a 0 49 0.0000 4.0000 1.0000 -test t1 c aaaa dddddddd 0.1250 6.6571 7.0000 -test t1 d 1989-03-12 1999-07-23 0.1500 3.0000 8.5000 -test t1 e 0.01 0.112 0.2250 8.0000 6.2000 -test t1 f 1 5 0.2000 1.0000 6.4000 -test t1 b NULL NULL 0.2000 17.1250 NULL -SELECT * FROM mysql.index_stats; -db_name table_name index_name prefix_arity avg_frequency -test t1 PRIMARY 1 1.0000 -test t1 idx3 1 8.5000 -test t1 idx2 1 7.0000 -test t1 idx2 2 2.3846 -test t1 idx1 1 NULL -test t1 idx1 2 NULL -test t1 idx4 1 6.2000 -test t1 idx4 2 NULL -test t1 idx4 3 NULL DELETE FROM mysql.table_stats; DELETE FROM mysql.column_stats; DELETE FROM mysql.index_stats; diff --git a/mysql-test/t/mdev-504.test b/mysql-test/t/mdev-504.test index 5193581cc47..bc38e99067a 100644 --- a/mysql-test/t/mdev-504.test +++ b/mysql-test/t/mdev-504.test @@ -1,3 +1,5 @@ +--disable_ps_protocol + CREATE TABLE A ( pk INTEGER AUTO_INCREMENT PRIMARY KEY, fdate DATE diff --git a/mysql-test/t/statistics.test b/mysql-test/t/statistics.test index 4537c4ed3f3..4f2d0510c11 100644 --- a/mysql-test/t/statistics.test +++ b/mysql-test/t/statistics.test @@ -368,22 +368,60 @@ SELECT * FROM mysql.table_stats; SELECT * FROM mysql.column_stats; SELECT * FROM mysql.index_stats; - CREATE TABLE t2 LIKE t1; ALTER TABLE t2 ENGINE=InnoDB; INSERT INTO t2 SELECT * FROM t1; +set optimizer_switch='extended_keys=off'; + ANALYZE TABLE t2; SELECT * FROM mysql.table_stats; SELECT * FROM mysql.column_stats ORDER BY column_name; SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; - DELETE FROM mysql.table_stats; DELETE FROM mysql.column_stats; DELETE FROM mysql.index_stats; +set optimizer_switch='extended_keys=on'; + +ANALYZE TABLE t2; + +SELECT * FROM mysql.table_stats; +SELECT * FROM mysql.column_stats ORDER BY column_name; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ALTER TABLE t2 DROP PRIMARY KEY, DROP INDEX idx1; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +UPDATE t2 SET b=0 WHERE b IS NULL; +ALTER TABLE t2 ADD PRIMARY KEY (a,b); +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ALTER TABLE t2 CHANGE COLUMN b b varchar(30); +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ALTER TABLE t2 CHANGE COLUMN b b varchar(32); +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ALTER TABLE t2 DROP COLUMN b; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL; +SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; + +set optimizer_switch='extended_keys=off'; + ALTER TABLE t1 DROP INDEX idx1, DROP INDEX idx4; @@ -392,6 +430,9 @@ ALTER TABLE t1 ADD INDEX idx1 (b(4), e), ADD INDEX idx4 (e, b(4), d); +SELECT * FROM mysql.column_stats; +SELECT * FROM mysql.index_stats; + ANALYZE TABLE t1; SELECT * FROM mysql.column_stats; @@ -411,7 +452,6 @@ SELECT * FROM mysql.index_stats; set use_stat_tables='never'; - ANALYZE TABLE t1 PERSISTENT FOR ALL; SELECT * FROM mysql.table_stats; @@ -419,11 +459,6 @@ SELECT * FROM mysql.column_stats; SELECT * FROM mysql.index_stats; -SELECT * FROM mysql.table_stats; -SELECT * FROM mysql.column_stats; -SELECT * FROM mysql.index_stats; - - DELETE FROM mysql.table_stats; DELETE FROM mysql.column_stats; DELETE FROM mysql.index_stats; diff --git a/sql/sql_base.h b/sql/sql_base.h index 71b4a9289ce..d45652927de 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -321,7 +321,8 @@ int alloc_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 delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info, + bool ext_prefixes_only); 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, diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index ce925a8fe96..f8f1175ac28 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2660,6 +2660,9 @@ int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col) tab The table the index belongs to @param key_info The descriptor of the index whose statistics is to be deleted + @param + ext_prefixes_only Delete statistics only on the index prefixes extended by + the components of the primary key @details The function delete statistics on the index specified by 'key_info' @@ -2675,7 +2678,8 @@ int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col) definition of a column used in the definition of the index. */ -int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info) +int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info, + bool ext_prefixes_only) { int err; bool save_binlog_row_based; @@ -2702,14 +2706,29 @@ int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info) stat_table= tables.table; Index_stat index_stat(stat_table, tab); - index_stat.set_index_prefix_key_fields(key_info); - while (index_stat.find_next_stat_for_prefix(3)) + if (!ext_prefixes_only) { - err= index_stat.delete_stat(); - if (err && !rc) - rc= 1; + index_stat.set_index_prefix_key_fields(key_info); + while (index_stat.find_next_stat_for_prefix(3)) + { + err= index_stat.delete_stat(); + if (err && !rc) + rc= 1; + } + } + else + { + for (uint i= key_info->key_parts; i < key_info->ext_key_parts; i++) + { + index_stat.set_key_fields(key_info, i+1); + if (index_stat.find_next_stat_for_prefix(4)) + { + err= index_stat.delete_stat(); + if (err && !rc) + rc= 1; + } + } } - if (save_binlog_row_based) thd->set_current_stmt_binlog_format_row(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index eb2a52e426c..b63c1859582 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5243,6 +5243,26 @@ mysql_compare_tables(TABLE *table, /* Evaluate changes bitmap and send to check_if_incompatible_data() */ if (!(tmp= field->is_equal(tmp_new_field))) { + if (table->s->tmp_table == NO_TMP_TABLE) + { + KEY *key_info= table->key_info; + for (uint i=0; i < table->s->keys; i++, key_info++) + { + if (field->part_of_key.is_set(i)) + { + uint key_parts= table->actual_n_key_parts(key_info); + for (uint j= 0; j < key_parts; j++) + { + if (key_info->key_part[j].fieldnr-1 == field->field_index) + { + (void) delete_statistics_for_index(thd, table, key_info, + j >= key_info->key_parts); + break; + } + } + } + } + } DBUG_PRINT("info", ("!field_is_equal('%s') -> ALTER_TABLE_DATA_CHANGED", new_field->field_name)); DBUG_RETURN(0); @@ -5342,7 +5362,20 @@ mysql_compare_tables(TABLE *table, field->flags|= FIELD_IN_ADD_INDEX; } if (table->s->tmp_table == NO_TMP_TABLE) - (void) delete_statistics_for_index(thd, table, table_key); + { + (void) delete_statistics_for_index(thd, table, table_key, FALSE); + if (table_key - table->key_info == table->s->primary_key) + { + KEY *tab_key_info= table->key_info; + for (uint j=0; j < table->s->keys; j++, tab_key_info++) + { + if (tab_key_info->key_parts != tab_key_info->ext_key_parts) + (void) delete_statistics_for_index(thd, table, tab_key_info, + TRUE); + } + } + } + DBUG_PRINT("info", ("index changed: '%s'", table_key->name)); } /*end of for (; table_key < table_key_end;) */ @@ -5544,6 +5577,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, uint used_fields= create_info->used_fields; KEY *key_info=table->key_info; bool rc= TRUE; + bool modified_primary_key= FALSE; Create_field *def; Field **f_ptr,*field; DBUG_ENTER("mysql_prepare_alter_table"); @@ -5740,7 +5774,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, Collect all keys which isn't in drop list. Add only those for which some fields exists. */ - + for (uint i=0 ; i < table->s->keys ; i++,key_info++) { char *key_name= key_info->name; @@ -5755,7 +5789,19 @@ 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); + { + (void) delete_statistics_for_index(thd, table, key_info, FALSE); + if (i == table->s->primary_key) + { + KEY *tab_key_info= table->key_info; + for (uint j=0; j < table->s->keys; j++, tab_key_info++) + { + if (tab_key_info->key_parts != tab_key_info->ext_key_parts) + (void) delete_statistics_for_index(thd, table, tab_key_info, + TRUE); + } + } + } drop_it.remove(); continue; } @@ -5786,6 +5832,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } if (!cfield) { + if (table->s->primary_key == i) + modified_primary_key= TRUE; delete_index_stat= TRUE; continue; // Field is removed } @@ -5830,8 +5878,15 @@ 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 (table->s->tmp_table == NO_TMP_TABLE) + { + if (delete_index_stat) + (void) delete_statistics_for_index(thd, table, key_info, FALSE); + else if (modified_primary_key && + key_info->key_parts != key_info->ext_key_parts) + (void) delete_statistics_for_index(thd, table, key_info, TRUE); + } + if (key_parts.elements) { KEY_CREATE_INFO key_create_info;