Skip to content

Commit

Permalink
MDEV-33087 ALTER TABLE...ALGORITHM=COPY should build indexes more eff…
Browse files Browse the repository at this point in the history
…iciently

- During copy algorithm, InnoDB should use bulk insert operation
for row by row insert operation. By doing this, copy algorithm
can effectively build indexes.
  • Loading branch information
Thirunarayanan committed Mar 25, 2024
1 parent a2dd4c1 commit f0ea2cf
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 16 deletions.
12 changes: 12 additions & 0 deletions mysql-test/main/rowid_filter.result
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,10 @@ o_orderkey l_linenumber l_shipdate o_totalprice
# MDEV-18413: find constraint correlated indexes
#
ALTER TABLE lineitem ADD CONSTRAINT l_date CHECK(l_shipdate < l_receiptdate);
ANALYZE TABLE lineitem;
Table Op Msg_type Msg_text
dbt3_s001.lineitem analyze status Engine-independent statistics collected
dbt3_s001.lineitem analyze status Table is already up to date
# Filter on l_shipdate is not used because it participates in
# the same constraint as l_receiptdate.
# Access is made on l_receiptdate.
Expand Down Expand Up @@ -1619,6 +1623,14 @@ ALTER TABLE orders ADD COLUMN o_totaldiscount double;
UPDATE orders SET o_totaldiscount = o_totalprice*(o_custkey/1000);
CREATE INDEX i_o_totaldiscount on orders(o_totaldiscount);
ALTER TABLE orders ADD CONSTRAINT o_price CHECK(o_totalprice > o_totaldiscount);
analyze table lineitem;
Table Op Msg_type Msg_text
dbt3_s001.lineitem analyze status Engine-independent statistics collected
dbt3_s001.lineitem analyze status Table is already up to date
analyze table orders;
Table Op Msg_type Msg_text
dbt3_s001.orders analyze status Engine-independent statistics collected
dbt3_s001.orders analyze status Table is already up to date
# Filter on o_totalprice is not used because it participates in
# the same constraint as o_discount.
# Access is made on o_discount.
Expand Down
5 changes: 5 additions & 0 deletions mysql-test/main/rowid_filter.test
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ eval $without_filter $q4;

ALTER TABLE lineitem ADD CONSTRAINT l_date CHECK(l_shipdate < l_receiptdate);

ANALYZE TABLE lineitem;

--echo # Filter on l_shipdate is not used because it participates in
--echo # the same constraint as l_receiptdate.
--echo # Access is made on l_receiptdate.
Expand Down Expand Up @@ -176,6 +178,9 @@ CREATE INDEX i_o_totaldiscount on orders(o_totaldiscount);

ALTER TABLE orders ADD CONSTRAINT o_price CHECK(o_totalprice > o_totaldiscount);

analyze table lineitem;
analyze table orders;

--echo # Filter on o_totalprice is not used because it participates in
--echo # the same constraint as o_discount.
--echo # Access is made on o_discount.
Expand Down
16 changes: 14 additions & 2 deletions mysql-test/main/rowid_filter_innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,10 @@ o_orderkey l_linenumber l_shipdate o_totalprice
# MDEV-18413: find constraint correlated indexes
#
ALTER TABLE lineitem ADD CONSTRAINT l_date CHECK(l_shipdate < l_receiptdate);
ANALYZE TABLE lineitem;
Table Op Msg_type Msg_text
dbt3_s001.lineitem analyze status Engine-independent statistics collected
dbt3_s001.lineitem analyze status OK
# Filter on l_shipdate is not used because it participates in
# the same constraint as l_receiptdate.
# Access is made on l_receiptdate.
Expand Down Expand Up @@ -1567,6 +1571,14 @@ ALTER TABLE orders ADD COLUMN o_totaldiscount double;
UPDATE orders SET o_totaldiscount = o_totalprice*(o_custkey/1000);
CREATE INDEX i_o_totaldiscount on orders(o_totaldiscount);
ALTER TABLE orders ADD CONSTRAINT o_price CHECK(o_totalprice > o_totaldiscount);
analyze table lineitem;
Table Op Msg_type Msg_text
dbt3_s001.lineitem analyze status Engine-independent statistics collected
dbt3_s001.lineitem analyze status OK
analyze table orders;
Table Op Msg_type Msg_text
dbt3_s001.orders analyze status Engine-independent statistics collected
dbt3_s001.orders analyze status OK
# Filter on o_totalprice is not used because it participates in
# the same constraint as o_discount.
# Access is made on o_discount.
Expand Down Expand Up @@ -1986,7 +1998,7 @@ ANALYZE
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"r_engine_stats": {
"pages_accessed": 3
"pages_accessed": 2
},
"filtered": "REPLACED",
"r_filtered": 66.66666667,
Expand Down Expand Up @@ -2140,7 +2152,7 @@ ANALYZE
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"r_engine_stats": {
"pages_accessed": 3
"pages_accessed": 2
},
"filtered": "REPLACED",
"r_filtered": 66.66666667,
Expand Down
7 changes: 7 additions & 0 deletions mysql-test/suite/parts/inc/partition_alter3.inc
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,18 @@ ALTER TABLE t1 ADD PARTITION (PARTITION part2);
#
--echo # 1.1.2 Assign HASH partitioning
ALTER TABLE t1 PARTITION BY HASH(YEAR(f_date));
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read1.inc
#
--echo # 1.1.3 Assign other HASH partitioning to already partitioned table
--echo # + test and switch back + test
ALTER TABLE t1 PARTITION BY HASH(DAYOFYEAR(f_date));
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read1.inc
ALTER TABLE t1 PARTITION BY HASH(YEAR(f_date));
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read1.inc
#
Expand All @@ -64,6 +67,7 @@ ALTER TABLE t1 ADD PARTITION (PARTITION part2 VALUES LESS THAN (0));
#
--echo # 1.1.5 Add two named partitions + test
ALTER TABLE t1 ADD PARTITION (PARTITION part1, PARTITION part7);
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read1.inc
#
Expand Down Expand Up @@ -111,6 +115,7 @@ ALTER TABLE t1 COALESCE PARTITION 1;
#
--echo # 1.2.6 Remove partitioning
ALTER TABLE t1 REMOVE PARTITIONING;
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read1.inc
#
Expand Down Expand Up @@ -154,6 +159,7 @@ ALTER TABLE t1 ADD PARTITION (PARTITION part2 VALUES LESS THAN (0));
#
--echo # 2.1.3 Add two named partitions + test
ALTER TABLE t1 ADD PARTITION (PARTITION part1, PARTITION part7);
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read2.inc
#
Expand All @@ -180,6 +186,7 @@ let $loop= 7;
while ($loop)
{
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
--source suite/parts/inc/partition_layout.inc
--source suite/parts/inc/partition_check_read2.inc
dec $loop;
Expand Down
56 changes: 54 additions & 2 deletions mysql-test/suite/parts/r/partition_alter3_innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ ALTER TABLE t1 ADD PARTITION (PARTITION part2);
ERROR HY000: Partition management on a not partitioned table is not possible
# 1.1.2 Assign HASH partitioning
ALTER TABLE t1 PARTITION BY HASH(YEAR(f_date));
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand All @@ -93,6 +97,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# 1.1.3 Assign other HASH partitioning to already partitioned table
# + test and switch back + test
ALTER TABLE t1 PARTITION BY HASH(DAYOFYEAR(f_date));
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand All @@ -110,6 +118,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 PARTITION BY HASH(YEAR(f_date));
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand All @@ -133,6 +145,10 @@ ALTER TABLE t1 ADD PARTITION (PARTITION part2 VALUES LESS THAN (0));
ERROR HY000: Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition
# 1.1.5 Add two named partitions + test
ALTER TABLE t1 ADD PARTITION (PARTITION part1, PARTITION part7);
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -392,7 +408,7 @@ t1.frm
t1.par
EXPLAIN PARTITIONS SELECT COUNT(*) FROM t1 WHERE f_date = '1000-02-10';
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 20 Using where
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where
# check read single success: 1
# check read all success: 1
# check read row by row success: 1
Expand All @@ -401,6 +417,10 @@ ALTER TABLE t1 COALESCE PARTITION 1;
ERROR HY000: Cannot remove all partitions, use DROP TABLE instead
# 1.2.6 Remove partitioning
ALTER TABLE t1 REMOVE PARTITIONING;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -477,7 +497,7 @@ t1.frm
t1.par
EXPLAIN PARTITIONS SELECT COUNT(*) <> 1 FROM t1 WHERE f_int1 = 3;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 20 Using where
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where
# check read single success: 1
# check read all success: 1
# check read row by row success: 1
Expand All @@ -488,6 +508,10 @@ ALTER TABLE t1 ADD PARTITION (PARTITION part2 VALUES LESS THAN (0));
ERROR HY000: Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition
# 2.1.3 Add two named partitions + test
ALTER TABLE t1 ADD PARTITION (PARTITION part1, PARTITION part7);
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -585,6 +609,10 @@ ALTER TABLE t1 DROP PARTITION part1;
ERROR HY000: DROP PARTITION can only be used on RANGE/LIST partitions
# 2.2.4 COALESCE one partition + test loop
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -618,6 +646,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -649,6 +681,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -678,6 +714,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down Expand Up @@ -705,6 +745,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand All @@ -730,6 +774,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand All @@ -753,6 +801,10 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
# check read all success: 1
# check read row by row success: 1
ALTER TABLE t1 COALESCE PARTITION 1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
Expand Down
12 changes: 11 additions & 1 deletion sql/sql_insert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4315,7 +4315,17 @@ bool select_insert::prepare_eof()
if (info.ignore || info.handle_duplicates != DUP_ERROR)
if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
table->file->ha_rnd_end();
table->file->extra(HA_EXTRA_END_ALTER_COPY);
int create_err= table->file->extra(HA_EXTRA_END_ALTER_COPY);
if (error <= 0)
{
if (create_err == HA_ERR_FOUND_DUPP_KEY)
{
uint key_nr= table->file->get_dup_key(create_err);
if ((int)key_nr >= 0 && key_nr < table->s->keys)
print_keydup_error(table, &table->key_info[key_nr], MYF(0));
}
error= create_err;
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);

Expand Down
14 changes: 11 additions & 3 deletions sql/sql_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12085,9 +12085,17 @@ 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 == HA_ERR_FOUND_DUPP_KEY)
{
uint key_nr= to->file->get_dup_key(alt_error);
if ((int)key_nr >= 0 && key_nr < to->s->keys)
print_keydup_error(to, &to->key_info[key_nr], MYF(0));
}
error= alt_error;
}
cleanup_done= 1;
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);

Expand Down
10 changes: 10 additions & 0 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15735,6 +15735,16 @@ ha_innobase::extra(
break;
case HA_EXTRA_END_ALTER_COPY:
trx = check_trx_exists(ha_thd());
if (m_prebuilt->table->skip_alter_undo) {
if (dberr_t err= trx->bulk_insert_apply()) {
if (err == DB_DUPLICATE_KEY) {
return HA_ERR_FOUND_DUPP_KEY;
}
return 1;
}
trx->end_bulk_insert(*m_prebuilt->table);
trx->bulk_insert = false;
}
m_prebuilt->table->skip_alter_undo = 0;
if (!m_prebuilt->table->is_temporary()
&& !high_level_read_only) {
Expand Down
2 changes: 1 addition & 1 deletion storage/innobase/handler/handler0alter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ inline void dict_table_t::rollback_instant(
}

/* Report an InnoDB error to the client by invoking my_error(). */
static ATTRIBUTE_COLD __attribute__((nonnull))
ATTRIBUTE_COLD __attribute__((nonnull))
void
my_error_innodb(
/*============*/
Expand Down
9 changes: 9 additions & 0 deletions storage/innobase/include/row0merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,15 @@ row_merge_read_rec(
ulint space) /*!< in: space id */
MY_ATTRIBUTE((warn_unused_result));

/* Report an InnoDB error to the client by invoking my_error(). */
ATTRIBUTE_COLD __attribute__((nonnull))
void
my_error_innodb(
/*============*/
dberr_t error, /*!< in: InnoDB error code */
const char* table, /*!< in: table name */
ulint flags); /*!< in: table flags */

/** Buffer for bulk insert */
class row_merge_bulk_t
{
Expand Down
4 changes: 2 additions & 2 deletions storage/innobase/include/trx0trx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1173,8 +1173,8 @@ struct trx_t : ilist_node<>
{
if (UNIV_LIKELY(!bulk_insert))
return nullptr;
ut_ad(!check_unique_secondary);
ut_ad(!check_foreigns);
ut_ad(table->skip_alter_undo || !check_unique_secondary);
ut_ad(table->skip_alter_undo || !check_foreigns);
auto it= mod_tables.find(table);
if (it == mod_tables.end() || !it->second.bulk_buffer_exist())
return nullptr;
Expand Down

0 comments on commit f0ea2cf

Please sign in to comment.