MDEV-27328 Change of SYSTEM_TIME partitioning options is not possible without data copy

When we need to add/remove or change LIMIT, INTERVAL, AUTO we have to
recreate partitioning from scratch (via data copy). Such operations
should be done fast. To remove options like LIMIT or INTERVAL one
should write:

  alter table t1 partition by system_time;

The command checks whether it is new or existing SYSTEM_TIME
partitioning. And in the case of new it behaves as CREATE would do:
adds default number of partitions (2). If SYSTEM_TIME partitioning
already existed it just changes its options: removes unspecified ones
and adds/changes those specified explicitly. In case when partitions
list was supplied it behaves as usual: does full repartitioning.

Examples:

  create or replace table t1 (x int) with system versioning
  partition by system_time limit 100 partitions 4;

  # Change LIMIT
  alter table t1 partition by system_time limit 33;

  # Remove LIMIT
  alter table t1 partition by system_time;

  # This does full repartitioning
  alter table t1 partition by system_time limit 33 partitions 4;

  # This does data copy as pruning will require records in correct partitions
  alter table t1 partition by system_time interval 1 hour
  starts '2000-01-01 00:00:00';

  # But this works fast, LIMIT will apply to DML commands
  alter table t1 partition by system_time limit 33;

To sum up, ALTER for SYSTEM_TIME partitioning does full repartitioning
when:

  - INTERVAL was added or changed;
  - partition list or partition number was specified;

Otherwise it does fast alter table.

Cleaned up dead condition in set_up_default_partitions().

Reviewed by:

  Oleksandr Byelkin <sanja@mariadb.com>
  Nikita Malyavin <nikitamalyavin@gmail.com>
This commit is contained in:
Aleksey Midenkov 2022-05-06 10:45:17 +03:00
parent 93e64d1f58
commit 75ede427e4
5 changed files with 230 additions and 4 deletions

View file

@ -1334,6 +1334,126 @@ t1 CREATE TABLE `t1` (
PARTITION `pn` CURRENT ENGINE = DEFAULT_ENGINE)
drop tables t1;
#
# MDEV-27328 Change of SYSTEM_TIME partitioning options is not possible without data copy
#
create or replace table t1 (f int) with system versioning
partition by hash(f);
alter table t1 partition by system_time;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME
PARTITIONS 2
create or replace table t1 (f int) with system versioning
partition by system_time;
alter table t1 partition by hash(f);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY HASH (`f`)
create or replace table t1 (x int) with system versioning;
alter table t1 partition by system_time;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME
PARTITIONS 2
create or replace table t1 (x int) with system versioning
partition by system_time limit 100 partitions 4;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME LIMIT 100
PARTITIONS 4
alter table t1 add partition partitions 2;
alter table t1 partition by system_time;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME
PARTITIONS 6
alter table t1 partition by system_time limit 33;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME LIMIT 33
PARTITIONS 6
set timestamp= unix_timestamp('2000-01-01 00:00:00');
insert t1 values (0);
set timestamp= unix_timestamp('2000-01-01 00:10:00');
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 01:00:00');
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 01:30:00');
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 02:00:00');
update t1 set x= x + 1;
alter table t1 partition by system_time interval 1 hour
starts '2000-01-01 00:00:00';
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00'
PARTITIONS 6
select * from t1 partition (p0);
x
0
select * from t1 partition (p1);
x
1
2
select * from t1 partition (p2);
x
3
select * from t1 partition (pn);
x
4
set timestamp= default;
alter table t1 partition by system_time limit 1;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`x` int(11) DEFAULT NULL
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME LIMIT 1
PARTITIONS 6
update t1 set x= x + 1;
update t1 set x= x + 1;
select * from t1 partition (p0);
x
0
select * from t1 partition (p1);
x
1
2
select * from t1 partition (p2);
x
3
select * from t1 partition (p3);
x
4
select * from t1 partition (p4);
x
5
select * from t1 partition (pn);
x
6
drop table t1;
#
# End of 10.5 tests
#
SET GLOBAL innodb_stats_persistent=@save_persistent;

View file

@ -1157,6 +1157,76 @@ drop tables t1;
--disable_prepare_warnings
--echo #
--echo # MDEV-27328 Change of SYSTEM_TIME partitioning options is not possible without data copy
--echo #
create or replace table t1 (f int) with system versioning
partition by hash(f);
alter table t1 partition by system_time;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
create or replace table t1 (f int) with system versioning
partition by system_time;
alter table t1 partition by hash(f);
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
create or replace table t1 (x int) with system versioning;
alter table t1 partition by system_time;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
create or replace table t1 (x int) with system versioning
partition by system_time limit 100 partitions 4;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
alter table t1 add partition partitions 2;
alter table t1 partition by system_time;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
alter table t1 partition by system_time limit 33;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
set timestamp= unix_timestamp('2000-01-01 00:00:00');
insert t1 values (0);
set timestamp= unix_timestamp('2000-01-01 00:10:00');
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 01:00:00');
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 01:30:00');
update t1 set x= x + 1;
set timestamp= unix_timestamp('2000-01-01 02:00:00');
update t1 set x= x + 1;
# When we switch to INTERVAL we must reorganize partitions.
# Otherwise pruning won't work correctly.
alter table t1 partition by system_time interval 1 hour
starts '2000-01-01 00:00:00';
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
select * from t1 partition (p0);
select * from t1 partition (p1);
select * from t1 partition (p2);
select * from t1 partition (pn);
set timestamp= default;
# When we switch to LIMIT we probably don't want to reorganize old partitions.
# Note: reorganize for LIMIT is broken, it pushes all history into first partition.
# TODO: MDEV-27337
alter table t1 partition by system_time limit 1;
--replace_result $default_engine DEFAULT_ENGINE
show create table t1;
update t1 set x= x + 1;
update t1 set x= x + 1;
select * from t1 partition (p0);
select * from t1 partition (p1);
select * from t1 partition (p2);
select * from t1 partition (p3);
select * from t1 partition (p4);
select * from t1 partition (pn);
drop table t1;
--echo #
--echo # End of 10.5 tests
--echo #

View file

@ -419,8 +419,6 @@ bool partition_info::set_up_default_partitions(THD *thd, handler *file,
const char *error_string;
if (part_type == RANGE_PARTITION)
error_string= "RANGE";
else if (part_type == VERSIONING_PARTITION)
error_string= "SYSTEM_TIME";
else
error_string= "LIST";
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);

View file

@ -46,13 +46,22 @@ struct Vers_part_info : public Sql_alloc
{
interval.type= INTERVAL_LAST;
}
Vers_part_info(Vers_part_info &src) :
Vers_part_info(const Vers_part_info &src) :
interval(src.interval),
limit(src.limit),
now_part(NULL),
hist_part(NULL)
{
}
Vers_part_info& operator= (const Vers_part_info &src)
{
interval= src.interval;
limit= src.limit;
auto_hist= src.auto_hist;
now_part= src.now_part;
hist_part= src.hist_part;
return *this;
}
bool initialized()
{
if (now_part)

View file

@ -5058,6 +5058,10 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"LIST", "IN");
}
/*
Adding history partitions to non-history partitioning or
non-history parittions to history partitioning is prohibited.
*/
else if (thd->work_part_info->part_type == VERSIONING_PARTITION ||
tab_part_info->part_type == VERSIONING_PARTITION)
{
@ -5340,6 +5344,7 @@ that are reorganised.
{
if (el->type == partition_element::CURRENT)
{
/* now_part is always last partition, we add it to the end of partitions list. */
it.remove();
now_part= el;
}
@ -5967,11 +5972,35 @@ the generated partition syntax in a correct manner.
{
partition_info *part_info= thd->work_part_info;
bool is_native_partitioned= FALSE;
if (tab_part_info && tab_part_info->part_type == VERSIONING_PARTITION &&
tab_part_info != part_info && part_info->part_type == VERSIONING_PARTITION &&
part_info->num_parts == 0)
{
if (part_info->vers_info->interval.is_set() &&
/* TODO: equivalent intervals like 1 hour and 60 mins should be considered equal */
memcmp(&part_info->vers_info->interval,
&tab_part_info->vers_info->interval,
sizeof(Vers_part_info::interval)))
{
/* If interval is changed we can not do fast alter */
tab_part_info= tab_part_info->get_clone(thd);
}
else
{
/* NOTE: fast_alter_partition_table() works on existing TABLE data. */
*fast_alter_table= true;
table->mark_table_for_reopen();
}
*tab_part_info->vers_info= *part_info->vers_info;
thd->work_part_info= part_info= tab_part_info;
*partition_changed= true;
}
/*
Need to cater for engine types that can handle partition without
using the partition handler.
*/
if (part_info != tab_part_info)
else if (part_info != tab_part_info)
{
if (part_info->fix_parser_data(thd))
{