1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-33087 ALTER TABLE...ALGORITHM=COPY should build indexes more efficiently

- During copy algorithm, InnoDB should use bulk insert operation
for row by row insert operation. By doing this, copy algorithm
can effectively build indexes. This optimization is disabled
for temporary table, versioning table and table which has
foreign key relation.

Introduced the variable innodb_alter_copy_bulk to allow
the bulk insert operation for copy alter operation
inside InnoDB. This is enabled by default

ha_innobase::extra(): HA_EXTRA_END_ALTER_COPY mode tries to apply
the buffered bulk insert operation, updates the non-persistent
table stats.

row_merge_bulk_t::write_to_index(): Update stat_n_rows after
applying the bulk insert operation

row_ins_clust_index_entry_low(): In case of copy algorithm,
switch to bulk insert operation.

copy_data_error_ignore(): Handles the error while copying
the data from source to target file.
This commit is contained in:
Thirunarayanan Balathandayuthapani
2024-07-30 11:59:01 +05:30
parent 2844895766
commit cc8eefb0dc
22 changed files with 325 additions and 91 deletions

View File

@ -11766,6 +11766,59 @@ bool mysql_trans_commit_alter_copy_data(THD *thd)
DBUG_RETURN(error);
}
/** Handle the error when copying data from source to target table.
@param error error code
@param ignore alter ignore statement
@param to target table handler
@param thd Mysql Thread
@param alter_ctx Runtime context for alter statement
@retval false in case of error
@retval true in case of skipping the row and continue alter operation */
static bool
copy_data_error_ignore(int &error, bool ignore, TABLE *to,
THD *thd, Alter_table_ctx *alter_ctx)
{
if (to->file->is_fatal_error(error, HA_CHECK_DUP))
{
/* Not a duplicate key error. */
to->file->print_error(error, MYF(0));
error= 1;
return false;
}
/* Duplicate key error. */
if (unlikely(alter_ctx->fk_error_if_delete_row))
{
/* We are trying to omit a row from the table which serves
as parent in a foreign key. This might have broken
referential integrity so emit an error. Note that we
can't ignore this error even if we are
executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but
doesn't allow to break unique or foreign key constraints, */
my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
alter_ctx->fk_error_id,
alter_ctx->fk_error_table);
return false;
}
if (ignore)
return true;
/* Ordinary ALTER TABLE. Report duplicate key error. */
uint key_nr= to->file->get_dup_key(error);
if (key_nr <= MAX_KEY)
{
const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME);
if (key_nr == 0 && to->s->keys > 0 &&
(to->key_info[0].key_part[0].field->flags &
AUTO_INCREMENT_FLAG))
err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE);
print_keydup_error(to,
key_nr >= to->s->keys ? NULL :
&to->key_info[key_nr],
err_msg, MYF(0));
}
else
to->file->print_error(error, MYF(0));
return false;
}
static int
copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore,
@ -12027,58 +12080,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore,
to->auto_increment_field_not_null= FALSE;
if (unlikely(error))
{
if (to->file->is_fatal_error(error, HA_CHECK_DUP))
{
/* Not a duplicate key error. */
to->file->print_error(error, MYF(0));
error= 1;
break;
}
else
{
/* Duplicate key error. */
if (unlikely(alter_ctx->fk_error_if_delete_row))
{
/*
We are trying to omit a row from the table which serves as parent
in a foreign key. This might have broken referential integrity so
emit an error. Note that we can't ignore this error even if we are
executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but
doesn't allow to break unique or foreign key constraints,
*/
my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
alter_ctx->fk_error_id,
alter_ctx->fk_error_table);
break;
}
if (ignore)
{
/* This ALTER IGNORE TABLE. Simply skip row and continue. */
to->file->restore_auto_increment(prev_insert_id);
delete_count++;
}
else
{
/* Ordinary ALTER TABLE. Report duplicate key error. */
uint key_nr= to->file->get_dup_key(error);
if ((int) key_nr >= 0)
{
const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME);
if (key_nr == 0 && to->s->keys > 0 &&
(to->key_info[0].key_part[0].field->flags &
AUTO_INCREMENT_FLAG))
err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE);
print_keydup_error(to,
key_nr >= to->s->keys ? NULL :
&to->key_info[key_nr],
err_msg, MYF(0));
}
else
to->file->print_error(error, MYF(0));
break;
}
}
if (!copy_data_error_ignore(error, ignore, to, thd, alter_ctx))
break;
DBUG_ASSERT(ignore);
to->file->restore_auto_increment(prev_insert_id);
delete_count++;
}
else
{
@ -12105,9 +12111,15 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore,
error= 1;
}
bulk_insert_started= 0;
if (!ignore)
to->file->extra(HA_EXTRA_END_ALTER_COPY);
if (!ignore && error <= 0)
{
int alt_error= to->file->extra(HA_EXTRA_END_ALTER_COPY);
if (alt_error > 0)
{
error= alt_error;
copy_data_error_ignore(error, false, to, thd, alter_ctx);
}
}
cleanup_done= 1;
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);