MDEV-24564 Statistics are lost after ALTER TABLE

Ever since commit 007f68c37f,
ALTER TABLE no longer invokes handler::open() after
handler::commit_inplace_alter_table().

ha_innobase::reload_statistics(): Reload or recompute statistics
after ALTER TABLE.

innodb_notify_tabledef_changed(): A new function to invoke
ha_innobase::reload_statistics().

handlerton::notify_tabledef_changed(): Add the parameter handler*
so that ha_innobase::reload_statistics() can be invoked.

ha_partition::notify_tabledef_changed(),
partition_notify_tabledef_changed(): Pass through the call
to any partitions or subpartitions.

This is based on code that was supplied by Monty.
This commit is contained in:
Marko Mäkelä 2021-01-28 14:15:01 +02:00
parent 744e9752d8
commit 6d1f1b61b5
10 changed files with 135 additions and 41 deletions

View file

@ -121,5 +121,19 @@ SELECT index_name, stat_name, stat_description
FROM mysql.innodb_index_stats
WHERE database_name = 'test' AND table_name = 't';
index_name stat_name stat_description
# MDEV-24564 FIXME: Do reload statistics after the above ALTER TABLE!
GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID
GEN_CLUST_INDEX n_leaf_pages Number of leaf pages in the index
GEN_CLUST_INDEX size Number of pages in the index
idxb n_diff_pfx01 b
idxb n_diff_pfx02 b,DB_ROW_ID
idxb n_leaf_pages Number of leaf pages in the index
idxb size Number of pages in the index
vidxe n_diff_pfx01 e
vidxe n_diff_pfx02 e,DB_ROW_ID
vidxe n_leaf_pages Number of leaf pages in the index
vidxe size Number of pages in the index
vidxf n_diff_pfx01 f
vidxf n_diff_pfx02 f,DB_ROW_ID
vidxf n_leaf_pages Number of leaf pages in the index
vidxf size Number of pages in the index
DROP TABLE t;

View file

@ -52,6 +52,5 @@ ALTER TABLE t DROP INDEX vidxcd;
SELECT index_name, stat_name, stat_description
FROM mysql.innodb_index_stats
WHERE database_name = 'test' AND table_name = 't';
-- echo # MDEV-24564 FIXME: Do reload statistics after the above ALTER TABLE!
DROP TABLE t;

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2005, 2019, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB
Copyright (c) 2009, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -92,6 +92,61 @@ static handler *partition_create_handler(handlerton *hton,
static uint partition_flags();
static alter_table_operations alter_table_flags(alter_table_operations flags);
int ha_partition::notify_tabledef_changed(LEX_CSTRING *db,
LEX_CSTRING *org_table_name,
LEX_CUSTRING *frm,
LEX_CUSTRING *version)
{
char from_buff[FN_REFLEN + 1], from_lc_buff[FN_REFLEN + 1];
const char *from_path, *name_buffer_ptr, *from;
int res= 0;
handler **file= m_file;
DBUG_ENTER("ha_partition::notify_tabledef_changed");
from= table->s->normalized_path.str;
/* setup m_name_buffer_ptr */
if (read_par_file(table->s->normalized_path.str))
DBUG_RETURN(1);
from_path= get_canonical_filename(*file, from, from_lc_buff);
name_buffer_ptr= m_name_buffer_ptr;
do
{
LEX_CSTRING table_name;
const char *table_name_ptr;
if (create_partition_name(from_buff, sizeof(from_buff),
from_path, name_buffer_ptr,
NORMAL_PART_NAME, FALSE))
res=1;
table_name_ptr= from_buff + dirname_length(from_buff);
lex_string_set3(&table_name, table_name_ptr, strlen(table_name_ptr));
if (((*file)->ht)->notify_tabledef_changed((*file)->ht, db, &table_name,
frm, version, *file))
res=1;
name_buffer_ptr= strend(name_buffer_ptr) + 1;
} while (*(++file));
DBUG_RETURN(res);
}
static int
partition_notify_tabledef_changed(handlerton *,
LEX_CSTRING *db,
LEX_CSTRING *table,
LEX_CUSTRING *frm,
LEX_CUSTRING *version,
handler *file)
{
DBUG_ENTER("partition_notify_tabledef_changed");
DBUG_RETURN(static_cast<ha_partition*>
(file)->notify_tabledef_changed(db, table, frm, version));
}
/*
If frm_error() is called then we will use this to to find out what file
extensions exist for the storage engine. This is also used by the default
@ -149,7 +204,9 @@ static int partition_initialize(void *p)
partition_hton->db_type= DB_TYPE_PARTITION_DB;
partition_hton->create= partition_create_handler;
partition_hton->partition_flags= partition_flags;
partition_hton->notify_tabledef_changed= partition_notify_tabledef_changed;
partition_hton->alter_table_flags= alter_table_flags;
partition_hton->flags= HTON_NOT_USER_SELECTABLE |
HTON_HIDDEN |
@ -211,25 +268,6 @@ static handler *partition_create_handler(handlerton *hton,
return file;
}
/*
HA_CAN_PARTITION:
Used by storage engines that can handle partitioning without this
partition handler
(Partition, NDB)
HA_CAN_UPDATE_PARTITION_KEY:
Set if the handler can update fields that are part of the partition
function.
HA_CAN_PARTITION_UNIQUE:
Set if the handler can handle unique indexes where the fields of the
unique key are not part of the fields of the partition function. Thus
a unique key can be set on all fields.
HA_USE_AUTO_PARTITION
Set if the handler sets all tables to be partitioned by default.
*/
static uint partition_flags()
{
return HA_CAN_PARTITION;

View file

@ -3,7 +3,7 @@
/*
Copyright (c) 2005, 2012, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB Corporation.
Copyright (c) 2009, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1617,6 +1617,9 @@ public:
return part_recs;
}
int notify_tabledef_changed(LEX_CSTRING *db, LEX_CSTRING *table,
LEX_CUSTRING *frm, LEX_CUSTRING *version);
friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2);
friend int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2);
bool can_convert_string(

View file

@ -2,7 +2,7 @@
#define HANDLER_INCLUDED
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB
Copyright (c) 2009, 2021, MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -1681,7 +1681,8 @@ struct handlerton
*/
int (*notify_tabledef_changed)(handlerton *hton, LEX_CSTRING *db,
LEX_CSTRING *table_name, LEX_CUSTRING *frm,
LEX_CUSTRING *org_tabledef_version);
LEX_CUSTRING *org_tabledef_version,
handler *file);
/*
System Versioning

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
Copyright (c) 2010, 2020, MariaDB
Copyright (c) 2010, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -7934,7 +7934,6 @@ static bool mysql_inplace_alter_table(THD *thd,
Alter_info *alter_info= ha_alter_info->alter_info;
bool reopen_tables= false;
bool res;
handlerton *hton;
const enum_alter_inplace_result inplace_supported=
ha_alter_info->inplace_supported;
@ -8145,20 +8144,22 @@ static bool mysql_inplace_alter_table(THD *thd,
/* Notify the engine that the table definition has changed */
hton= table->file->partition_ht();
if (hton->notify_tabledef_changed)
if (table->file->partition_ht()->notify_tabledef_changed)
{
char db_buff[FN_REFLEN], table_buff[FN_REFLEN];
handlerton *hton= table->file->ht;
LEX_CSTRING tmp_db, tmp_table;
tmp_db.str= db_buff;
tmp_table.str= table_buff;
tmp_db.str= db_buff;
tmp_table.str= table_buff;
tmp_db.length= tablename_to_filename(table_list->db.str,
db_buff, sizeof(db_buff));
tmp_table.length= tablename_to_filename(table_list->table_name.str,
table_buff, sizeof(table_buff));
if ((hton->notify_tabledef_changed)(hton, &tmp_db, &tmp_table,
table->s->frm_image,
&table->s->tabledef_version))
&table->s->tabledef_version,
table->file))
{
my_error(HA_ERR_INCOMPATIBLE_DEFINITION, MYF(0));
DBUG_RETURN(true);

View file

@ -1330,6 +1330,30 @@ innobase_show_status(
stat_print_fn* stat_print,
enum ha_stat_type stat_type);
/** After ALTER TABLE, recompute statistics. */
inline void ha_innobase::reload_statistics()
{
if (dict_table_t *table= m_prebuilt ? m_prebuilt->table : nullptr)
{
if (table->is_readable())
dict_stats_init(table);
else
table->stat_initialized= 1;
}
}
/** After ALTER TABLE, recompute statistics. */
static int innodb_notify_tabledef_changed(handlerton *,
LEX_CSTRING *, LEX_CSTRING *,
LEX_CUSTRING *, LEX_CUSTRING *,
handler *handler)
{
DBUG_ENTER("innodb_notify_tabledef_changed");
if (handler)
static_cast<ha_innobase*>(handler)->reload_statistics();
DBUG_RETURN(0);
}
/****************************************************************//**
Parse and enable InnoDB monitor counters during server startup.
User can enable monitor counters/groups by specifying
@ -3816,6 +3840,7 @@ static int innodb_init(void* p)
innobase_hton->flush_logs = innobase_flush_logs;
innobase_hton->show_status = innobase_show_status;
innobase_hton->notify_tabledef_changed= innodb_notify_tabledef_changed;
innobase_hton->flags =
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS
| HTON_NATIVE_SYS_VERSIONING | HTON_WSREP_REPLICATION;
@ -16233,6 +16258,7 @@ innobase_show_status(
/* Success */
return(false);
}
/*********************************************************************//**
Returns number of THR_LOCK locks used for one instance of InnoDB table.
InnoDB no longer relies on THR_LOCK locks so 0 value is returned.

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -211,6 +211,8 @@ public:
int check(THD* thd, HA_CHECK_OPT* check_opt) override;
char* update_table_comment(const char* comment) override;
inline void reload_statistics();
char* get_foreign_key_create_info() override;
int get_foreign_key_list(THD *thd,

View file

@ -11263,12 +11263,18 @@ foreign_fail:
&& m_prebuilt->table->n_v_cols
&& ha_alter_info->handler_flags & ALTER_STORED_COLUMN_ORDER)) {
DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1);
ut_ad(ctx0->prebuilt == m_prebuilt);
trx_commit_for_mysql(m_prebuilt->trx);
m_prebuilt->table = innobase_reload_table(m_user_thd,
m_prebuilt->table,
table->s->table_name,
*ctx0);
for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx;
pctx++) {
auto ctx= static_cast<ha_innobase_inplace_ctx*>(*pctx);
ctx->prebuilt->table = innobase_reload_table(
m_user_thd, ctx->prebuilt->table,
table->s->table_name, *ctx0);
innobase_copy_frm_flags_from_table_share(
ctx->prebuilt->table, altered_table->s);
}
row_mysql_unlock_data_dictionary(trx);
trx->free();

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2019, 2020 MariaDB Corporation Ab
/* Copyright (C) 2019, 2021 MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -887,10 +887,11 @@ int ha_s3::discover_check_version()
Update the .frm file in S3
*/
static int s3_notify_tabledef_changed(handlerton *hton __attribute__((unused)),
static int s3_notify_tabledef_changed(handlerton *,
LEX_CSTRING *db, LEX_CSTRING *table,
LEX_CUSTRING *frm,
LEX_CUSTRING *org_tabledef_version)
LEX_CUSTRING *org_tabledef_version,
handler *)
{
char aws_path[AWS_PATH_LENGTH];
S3_INFO s3_info;
@ -898,6 +899,9 @@ static int s3_notify_tabledef_changed(handlerton *hton __attribute__((unused)),
int error= 0;
DBUG_ENTER("s3_notify_tabledef_changed");
if (strstr(table->str, "#P#"))
DBUG_RETURN(0); // Ignore partitions
if (s3_info_init(&s3_info))
DBUG_RETURN(0);
if (!(s3_client= s3_open_connection(&s3_info)))
@ -916,7 +920,7 @@ static int s3_notify_tabledef_changed(handlerton *hton __attribute__((unused)),
NullS);
if (s3_put_object(s3_client, s3_info.bucket.str, aws_path, (uchar*) frm->str,
frm->length, 0))
frm->length, 0))
error= 2;
err: