Change the large running table to a partitioned table
The code of this article is limited to monthly horizontal partition based on data time. Other requirements can be implemented by modifying the code
1. Create a partition table
The table field of this table is the same as that of the original table, with partition
CREATE TABLE `metric_data_tmp` ( id bigint primary key auto_increment, metric varchar(128), datadt datetime not null unqine, value decimal(30, 6) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 partition by range (to_days(DATADT)) ( PARTITION p201811 VALUES LESS THAN (to_days("2018-12-01")), PARTITION p201812 VALUES LESS THAN (to_days("2019-01-01")), PARTITION p201901 VALUES LESS THAN (to_days("2019-02-01")), PARTITION p201902 VALUES LESS THAN (to_days("2019-03-01")), );
2. Copy the original table data to the temporary table
- Directly through the insert statement
insert into metric_data_tmp select * from metric_data;
- The data volume is very large. You can use select into outfile and load data file to export and import
SELECT * INTO OUTFILE 'data.txt' FIELDS TERMINATED BY ',' FROM metric_data; LOAD DATA INFILE 'data.txt' INTO TABLE metric_data_tmp FIELDS TERMINATED BY ',';
3. Rename partition table and history table:
rename table metric_data to metric_data_bak; rename table metric_data_tmp to metric_data;
4. Automatically create the partition of next month through the scheduled task of database
- stored procedure
delimiter $$ use `db_orbit`$$ drop procedure if exists `create_partition_by_month`$$ create procedure `create_partition_by_month`(in_schemaname varchar(64), in_tablename varchar(64)) begin # Used to determine whether the table partition to be created already exists declare rows_cnt int unsigned; # Time to create table partition declare target_date timestamp; #The name of the partition in the format p201811 declare partition_name varchar(8); #Partition to be created next month set target_date = date_add(now(), interval 1 month); set partition_name = date_format( target_date, 'p%Y%m' ); # Determine whether the partition to be created exists select count(1) into rows_cnt from information_schema.partitions t where table_schema = in_schemaname and table_name = in_tablename and ifnull(t.partition_name, '') = partition_name; if rows_cnt = 0 then set @sql = concat( 'alter table `', in_schemaname, '`.`', in_tablename, '`', ' add partition (partition ', partition_name, " values less than (to_days('", date_format(DATE_ADD(target_date, INTERVAL 1 month), '%Y-%m-01'), "')) engine = innodb);" ); prepare stmt from @sql; execute stmt; deallocate prepare stmt; else select concat("partition `", partition_name, "` for table `",in_schemaname, ".", in_tablename, "` already exists") as result; end if; end$$ delimiter ;
- Create scheduled tasks and execute stored procedures regularly to create partitions
DELIMITER $$ #The database name of the table USE `db_orbit`$$ CREATE EVENT IF NOT EXISTS `generate_partition_for_metric_data` ON SCHEDULE EVERY 1 MONTH #Execution cycle, days, months, etc STARTS '2019-03-15 00:00:00' ON COMPLETION PRESERVE ENABLE COMMENT 'Creating partitions' DO BEGIN #Call the stored procedure you just created. The first parameter is the database name, and the second parameter is the table name CALL db_orbit.create_partition_by_month('db_orbit', 'metric_data'); END$$ DELIMITER ;
5. other
- SQL to view table partition
select partition_name part, partition_expression expr, partition_description descr, table_rows from information_schema.partitions where table_name='metric_data';