最近遇到一個問題,就是如何自動刪除6個月以前的舊的分區。就MariaDB而言,並無相似機制,可讓咱們開箱即用,去完成這件事情。因此咱們須要換一種思路,或許問題就能夠很簡單的被解決。咱們能夠建立一個存儲過程和一個事件,而後按照預約的時間表來調用這個存儲過程。實際上,咱們還能夠進一步建立一個存儲過程,讓該過程自動添加新的分區。sql
在本篇文章中,咱們將展現如何編寫執行這些任務的存儲過程。oop
在該演示中,咱們將使用MySQL文檔RANGE分區示例給出的數據表,稍作一些改動:測試
DROP TABLE IF EXISTS db1.quarterly_report_status; CREATE TABLE db1.quarterly_report_status ( report_id INT NOT NULL, report_status VARCHAR(20) NOT NULL, report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) ( PARTITION p_first VALUES LESS THAN ( UNIX_TIMESTAMP('2016-10-01 00:00:00')), PARTITION p201610 VALUES LESS THAN ( UNIX_TIMESTAMP('2016-11-01 00:00:00')), PARTITION p201611 VALUES LESS THAN ( UNIX_TIMESTAMP('2016-12-01 00:00:00')), PARTITION p201612 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-01-01 00:00:00')), PARTITION p201701 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-02-01 00:00:00')), PARTITION p201702 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-03-01 00:00:00')), PARTITION p201703 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-04-01 00:00:00')), PARTITION p201704 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-05-01 00:00:00')), PARTITION p201705 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-06-01 00:00:00')), PARTITION p201706 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-07-01 00:00:00')), PARTITION p201707 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-08-01 00:00:00')), PARTITION p201708 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-09-01 00:00:00')), PARTITION p_future VALUES LESS THAN (MAXVALUE) );
最重要的改動是分區命名方案是基於日期的。這將使咱們更容易地肯定要刪除哪些分區。ui
存儲過程自己也會包含一些註釋,來講明它所做的事情。須要提出說明的是,咱們沒有使用 ALTER TABLE ... ADD PARTITION
這樣的語句,由於 p_future 分區已經覆蓋了到 MAXVALUE 的結束範圍。因此咱們須要使用 ALTER TABLE ... REORGANIZE PARTITION
語句來代替。this
DROP PROCEDURE IF EXISTS db1.create_new_partitions; DELIMITER $ CREATE PROCEDURE db1.create_new_partitions(p_schema varchar(64), p_table varchar(64), p_months_to_add int) LANGUAGE SQL NOT DETERMINISTIC SQL SECURITY INVOKER BEGIN DECLARE done INT DEFAULT FALSE; DECLARE current_partition_name varchar(64); DECLARE current_partition_ts int; -- We'll use this cursor later to check -- whether a particular already exists. -- @partition_name_to_add will be -- set later. DECLARE cur1 CURSOR FOR SELECT partition_name FROM information_schema.partitions WHERE TABLE_SCHEMA = p_schema AND TABLE_NAME = p_table AND PARTITION_NAME != 'p_first' AND PARTITION_NAME != 'p_future' AND PARTITION_NAME = @partition_name_to_add; -- We'll also use this cursor later -- to query our temporary table. DECLARE cur2 CURSOR FOR SELECT partition_name, partition_range_ts FROM partitions_to_add; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; DROP TEMPORARY TABLE IF EXISTS partitions_to_add; CREATE TEMPORARY TABLE partitions_to_add ( partition_name varchar(64), partition_range_ts int ); SET @partitions_added = FALSE; SET @months_ahead = 0; -- Let's go through a loop and add each month individually between -- the current month and the month p_months_to_add in the future. WHILE @months_ahead <= p_months_to_add DO -- We figure out what the correct month is by adding the -- number of months to the current date SET @date = CURDATE(); SET @q = 'SELECT DATE_ADD(?, INTERVAL ? MONTH) INTO @month_to_add'; PREPARE st FROM @q; EXECUTE st USING @date, @months_ahead; DEALLOCATE PREPARE st; SET @months_ahead = @months_ahead + 1; -- Then we format the month in the same format used -- in our partition names. SET @q = 'SELECT DATE_FORMAT(@month_to_add, ''%Y%m'') INTO @formatted_month_to_add'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; -- And then we use the formatted date to build the name of the -- partition that we want to add. This partition name is -- assigned to @partition_name_to_add, which is used in -- the cursor declared at the start of the procedure. SET @q = 'SELECT CONCAT(''p'', @formatted_month_to_add) INTO @partition_name_to_add'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; SET done = FALSE; SET @first = TRUE; -- And then we loop through the results returned by the cursor, -- and if a row already exists for the current partition, -- then we do not need to create the partition. OPEN cur1; read_loop: LOOP FETCH cur1 INTO current_partition_name; -- The cursor returned 0 rows, so we can create the partition. IF done AND @first THEN SELECT CONCAT('Creating partition: ', @partition_name_to_add); -- Now we need to get the end date of the new partition. -- Note that the date is for the non-inclusive end range, -- so we actually need the date of the first day of the *next* month. -- First, let's get a date variable for the first of the partition month SET @q = 'SELECT DATE_FORMAT(@month_to_add, ''%Y-%m-01 00:00:00'') INTO @month_to_add'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; -- Then, let's add 1 month SET @q = 'SELECT DATE_ADD(?, INTERVAL 1 MONTH) INTO @partition_end_date'; PREPARE st FROM @q; EXECUTE st USING @month_to_add; DEALLOCATE PREPARE st; -- We need the date in UNIX timestamp format. SELECT UNIX_TIMESTAMP(@partition_end_date) INTO @partition_end_ts; -- Now insert the information into our temporary table INSERT INTO partitions_to_add VALUES (@partition_name_to_add, @partition_end_ts); SET @partitions_added = TRUE; END IF; -- Since we had at least one row returned, we know the -- partition already exists. IF ! @first THEN LEAVE read_loop; END IF; SET @first = FALSE; END LOOP; CLOSE cur1; END WHILE; -- Let's actually add the partitions now. IF @partitions_added THEN -- First we need to build the actual ALTER TABLE query. SET @schema = p_schema; SET @table = p_table; SET @q = 'SELECT CONCAT(''ALTER TABLE '', @schema, ''.'', @table, '' REORGANIZE PARTITION p_future INTO ( '') INTO @query'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; SET done = FALSE; SET @first = TRUE; OPEN cur2; read_loop: LOOP FETCH cur2 INTO current_partition_name, current_partition_ts; IF done THEN LEAVE read_loop; END IF; -- If it is not the first partition, -- then we need to add a comma IF ! @first THEN SET @q = 'SELECT CONCAT(@query, '', '') INTO @query'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; END IF; -- Add the current partition SET @partition_name = current_partition_name; SET @partition_ts = current_partition_ts; SET @q = 'SELECT CONCAT(@query, ''PARTITION '', @partition_name, '' VALUES LESS THAN ('', @partition_ts, '')'') INTO @query'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; SET @first = FALSE; END LOOP; CLOSE cur2; -- We also need to include the p_future partition SET @q = 'SELECT CONCAT(@query, '', PARTITION p_future VALUES LESS THAN (MAXVALUE))'') INTO @query'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; -- And then we prepare and execute the ALTER TABLE query. PREPARE st FROM @query; EXECUTE st; DEALLOCATE PREPARE st; END IF; DROP TEMPORARY TABLE partitions_to_add; END$ DELIMITER ;
讓咱們運行一下新的過程:spa
MariaDB [db1]> SHOW CREATE TABLE db1.quarterly_report_status\G *************************** 1. row *************************** Table: quarterly_report_status Create Table: CREATE TABLE `quarterly_report_status` ( `report_id` int(11) NOT NULL, `report_status` varchar(20) NOT NULL, `report_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated)) (PARTITION p_first VALUES LESS THAN (1475294400) ENGINE = InnoDB, PARTITION p201610 VALUES LESS THAN (1477972800) ENGINE = InnoDB, PARTITION p201611 VALUES LESS THAN (1480568400) ENGINE = InnoDB, PARTITION p201612 VALUES LESS THAN (1483246800) ENGINE = InnoDB, PARTITION p201701 VALUES LESS THAN (1485925200) ENGINE = InnoDB, PARTITION p201702 VALUES LESS THAN (1488344400) ENGINE = InnoDB, PARTITION p201703 VALUES LESS THAN (1491019200) ENGINE = InnoDB, PARTITION p201704 VALUES LESS THAN (1493611200) ENGINE = InnoDB, PARTITION p201705 VALUES LESS THAN (1496289600) ENGINE = InnoDB, PARTITION p201706 VALUES LESS THAN (1498881600) ENGINE = InnoDB, PARTITION p201707 VALUES LESS THAN (1501560000) ENGINE = InnoDB, PARTITION p201708 VALUES LESS THAN (1504238400) ENGINE = InnoDB, PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 1 row in set (0.00 sec) MariaDB [db1]> CALL db1.create_new_partitions('db1', 'quarterly_report_status', 3); +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201709 | +--------------------------------------------------------+ 1 row in set (0.01 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201710 | +--------------------------------------------------------+ 1 row in set (0.02 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201711 | +--------------------------------------------------------+ 1 row in set (0.02 sec) Query OK, 0 rows affected (0.09 sec) MariaDB [db1]> SHOW CREATE TABLE db1.quarterly_report_status\G *************************** 1. row *************************** Table: quarterly_report_status Create Table: CREATE TABLE `quarterly_report_status` ( `report_id` int(11) NOT NULL, `report_status` varchar(20) NOT NULL, `report_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated)) (PARTITION p_first VALUES LESS THAN (1475294400) ENGINE = InnoDB, PARTITION p201610 VALUES LESS THAN (1477972800) ENGINE = InnoDB, PARTITION p201611 VALUES LESS THAN (1480568400) ENGINE = InnoDB, PARTITION p201612 VALUES LESS THAN (1483246800) ENGINE = InnoDB, PARTITION p201701 VALUES LESS THAN (1485925200) ENGINE = InnoDB, PARTITION p201702 VALUES LESS THAN (1488344400) ENGINE = InnoDB, PARTITION p201703 VALUES LESS THAN (1491019200) ENGINE = InnoDB, PARTITION p201704 VALUES LESS THAN (1493611200) ENGINE = InnoDB, PARTITION p201705 VALUES LESS THAN (1496289600) ENGINE = InnoDB, PARTITION p201706 VALUES LESS THAN (1498881600) ENGINE = InnoDB, PARTITION p201707 VALUES LESS THAN (1501560000) ENGINE = InnoDB, PARTITION p201708 VALUES LESS THAN (1504238400) ENGINE = InnoDB, PARTITION p201709 VALUES LESS THAN (1506830400) ENGINE = InnoDB, PARTITION p201710 VALUES LESS THAN (1509508800) ENGINE = InnoDB, PARTITION p201711 VALUES LESS THAN (1512104400) ENGINE = InnoDB, PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 1 row in set (0.00 sec)
咱們能夠看到,跟咱們預期的效果是同樣的。code
如下存儲過程也包含一些註釋,解釋它的做用。orm
值得指出的是,該存儲過程,經過 ALTER TABLE ... DROP PARTITION
語句分別刪除舊分區。而後經過 ALTER TABLE ... REORGANIZE PARTITION
語句增長了 p_first 分區的範圍,這樣就填補了後面留下的空白。事件
DROP PROCEDURE IF EXISTS db1.drop_old_partitions; DELIMITER $ CREATE PROCEDURE db1.drop_old_partitions(p_schema varchar(64), p_table varchar(64), p_months_to_keep int, p_seconds_to_sleep int) LANGUAGE SQL NOT DETERMINISTIC SQL SECURITY INVOKER BEGIN DECLARE done INT DEFAULT FALSE; DECLARE current_partition_name varchar(64); -- We'll use this cursor later to get -- the list of partitions to drop. -- @last_partition_name_to_keep will be -- set later. DECLARE cur1 CURSOR FOR SELECT partition_name FROM information_schema.partitions WHERE TABLE_SCHEMA = p_schema AND TABLE_NAME = p_table AND PARTITION_NAME != 'p_first' AND PARTITION_NAME != 'p_future' AND PARTITION_NAME < @last_partition_name_to_keep; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- Now we get the last month of data that we want to keep -- by subtracting p_months_to_keep from the current date. -- Note that it will actually keep p_months_to_keep+1 partitions, -- since the current month is not complete. SET @date = CURDATE(); SET @months_to_keep = p_months_to_keep; SET @q = 'SELECT DATE_SUB(?, INTERVAL ? MONTH) INTO @last_month_to_keep'; PREPARE st FROM @q; EXECUTE st USING @date, @months_to_keep; DEALLOCATE PREPARE st; -- Then we format the last month in the same format used -- in our partition names. SET @q = 'SELECT DATE_FORMAT(@last_month_to_keep, ''%Y%m'') INTO @formatted_last_month_to_keep'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; -- And then we use the formatted date to build the name of the -- last partition that we want to keep. This partition name is -- assigned to @last_partition_name_to_keep, which is used in -- the cursor declared at the start of the procedure. SET @q = 'SELECT CONCAT(''p'', @formatted_last_month_to_keep) INTO @last_partition_name_to_keep'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; SELECT CONCAT('Dropping all partitions before: ', @last_partition_name_to_keep); SET @first = TRUE; -- And then we loop through all partitions returned by the cursor, -- and those partitions are dropped. OPEN cur1; read_loop: LOOP FETCH cur1 INTO current_partition_name; IF done THEN LEAVE read_loop; END IF; IF ! @first AND p_seconds_to_sleep > 0 THEN SELECT CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds'); SELECT SLEEP(p_seconds_to_sleep); END IF; SELECT CONCAT('Dropping partition: ', current_partition_name); -- First we build the ALTER TABLE query. SET @schema = p_schema; SET @table = p_table; SET @partition = current_partition_name; SET @q = 'SELECT CONCAT(''ALTER TABLE '', @schema, ''.'', @table, '' DROP PARTITION '', @partition) INTO @query'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; -- And then we prepare and execute the ALTER TABLE query. PREPARE st FROM @query; EXECUTE st; DEALLOCATE PREPARE st; SET @first = FALSE; END LOOP; CLOSE cur1; -- If no partitions were dropped, then we can also skip this. IF ! @first THEN -- Then we need to get the date of the new first partition. -- We need the date in UNIX timestamp format. SET @q = 'SELECT DATE_FORMAT(@last_month_to_keep, ''%Y-%m-01 00:00:00'') INTO @new_first_partition_date'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; SELECT UNIX_TIMESTAMP(@new_first_partition_date) INTO @new_first_partition_ts; -- We also need to get the date of the second partition -- since the second partition is also needed for REORGANIZE PARTITION. SET @q = 'SELECT DATE_ADD(@new_first_partition_date, INTERVAL 1 MONTH) INTO @second_partition_date'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; SELECT UNIX_TIMESTAMP(@second_partition_date) INTO @second_partition_ts; SELECT CONCAT('Reorganizing first and second partitions. first partition date = ', @new_first_partition_date, ', second partition date = ', @second_partition_date); -- Then we build the ALTER TABLE query. SET @schema = p_schema; SET @table = p_table; SET @q = 'SELECT CONCAT(''ALTER TABLE '', @schema, ''.'', @table, '' REORGANIZE PARTITION p_first, '', @last_partition_name_to_keep, '' INTO ( PARTITION p_first VALUES LESS THAN ( '', @new_first_partition_ts, '' ), PARTITION '', @last_partition_name_to_keep, '' VALUES LESS THAN ( '', @second_partition_ts, '' ) ) '') INTO @query'; PREPARE st FROM @q; EXECUTE st; DEALLOCATE PREPARE st; -- And then we prepare and execute the ALTER TABLE query. PREPARE st FROM @query; EXECUTE st; DEALLOCATE PREPARE st; END IF; END$ DELIMITER ;
讓咱們運行一下新的過程:ip
MariaDB [db1]> SHOW CREATE TABLE db1.quarterly_report_status\G *************************** 1. row *************************** Table: quarterly_report_status Create Table: CREATE TABLE `quarterly_report_status` ( `report_id` int(11) NOT NULL, `report_status` varchar(20) NOT NULL, `report_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated)) (PARTITION p_first VALUES LESS THAN (1475294400) ENGINE = InnoDB, PARTITION p201610 VALUES LESS THAN (1477972800) ENGINE = InnoDB, PARTITION p201611 VALUES LESS THAN (1480568400) ENGINE = InnoDB, PARTITION p201612 VALUES LESS THAN (1483246800) ENGINE = InnoDB, PARTITION p201701 VALUES LESS THAN (1485925200) ENGINE = InnoDB, PARTITION p201702 VALUES LESS THAN (1488344400) ENGINE = InnoDB, PARTITION p201703 VALUES LESS THAN (1491019200) ENGINE = InnoDB, PARTITION p201704 VALUES LESS THAN (1493611200) ENGINE = InnoDB, PARTITION p201705 VALUES LESS THAN (1496289600) ENGINE = InnoDB, PARTITION p201706 VALUES LESS THAN (1498881600) ENGINE = InnoDB, PARTITION p201707 VALUES LESS THAN (1501560000) ENGINE = InnoDB, PARTITION p201708 VALUES LESS THAN (1504238400) ENGINE = InnoDB, PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 1 row in set (0.00 sec) MariaDB [db1]> CALL db1.drop_old_partitions('db1', 'quarterly_report_status', 6, 5); +--------------------------------------------------------------------------+ | CONCAT('Dropping all partitions before: ', @last_partition_name_to_keep) | +--------------------------------------------------------------------------+ | Dropping all partitions before: p201702 | +--------------------------------------------------------------------------+ 1 row in set (0.00 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201610 | +--------------------------------------------------------+ 1 row in set (0.00 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (0.02 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (5.02 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201611 | +--------------------------------------------------------+ 1 row in set (5.02 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (5.03 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (10.03 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201612 | +--------------------------------------------------------+ 1 row in set (10.03 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (10.05 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (15.05 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201701 | +--------------------------------------------------------+ 1 row in set (15.05 sec) +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | CONCAT('Reorganizing first and second partitions. first partition date = ', @new_first_partition_date, ', second partition date = ', @second_partition_date) | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Reorganizing first and second partitions. first partition date = 2017-02-01 00:00:00, second partition date = 2017-03-01 00:00:00 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (15.06 sec) Query OK, 0 rows affected (15.11 sec) MariaDB [db1]> SHOW CREATE TABLE db1.quarterly_report_status\G *************************** 1. row *************************** Table: quarterly_report_status Create Table: CREATE TABLE `quarterly_report_status` ( `report_id` int(11) NOT NULL, `report_status` varchar(20) NOT NULL, `report_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated)) (PARTITION p_first VALUES LESS THAN (1485925200) ENGINE = InnoDB, PARTITION p201702 VALUES LESS THAN (1488344400) ENGINE = InnoDB, PARTITION p201703 VALUES LESS THAN (1491019200) ENGINE = InnoDB, PARTITION p201704 VALUES LESS THAN (1493611200) ENGINE = InnoDB, PARTITION p201705 VALUES LESS THAN (1496289600) ENGINE = InnoDB, PARTITION p201706 VALUES LESS THAN (1498881600) ENGINE = InnoDB, PARTITION p201707 VALUES LESS THAN (1501560000) ENGINE = InnoDB, PARTITION p201708 VALUES LESS THAN (1504238400) ENGINE = InnoDB, PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 1 row in set (0.00 sec)
咱們能夠看到,正如咱們所預期的,除了舊的分區被刪除,咱們還能夠看到 p_first 的日期範圍也被更新了。
在大多數狀況下,同一時間執行全部分區維護可能會更好。所以,咱們能夠建立另外一個存儲過程,調用咱們的其餘兩個存儲過程。
DROP PROCEDURE IF EXISTS db1.perform_partition_maintenance; DELIMITER $ CREATE PROCEDURE db1.perform_partition_maintenance(p_schema varchar(64), p_table varchar(64), p_months_to_add int, p_months_to_keep int, p_seconds_to_sleep int) LANGUAGE SQL NOT DETERMINISTIC SQL SECURITY INVOKER BEGIN CALL db1.drop_old_partitions(p_schema, p_table, p_months_to_keep, p_seconds_to_sleep); CALL db1.create_new_partitions(p_schema, p_table, p_months_to_add); END$ DELIMITER ;
咱們將分區表從新設置爲原來的狀態,而後運行新的存儲過程。
MariaDB [db1]> SHOW CREATE TABLE db1.quarterly_report_status\G *************************** 1. row *************************** Table: quarterly_report_status Create Table: CREATE TABLE `quarterly_report_status` ( `report_id` int(11) NOT NULL, `report_status` varchar(20) NOT NULL, `report_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated)) (PARTITION p_first VALUES LESS THAN (1475294400) ENGINE = InnoDB, PARTITION p201610 VALUES LESS THAN (1477972800) ENGINE = InnoDB, PARTITION p201611 VALUES LESS THAN (1480568400) ENGINE = InnoDB, PARTITION p201612 VALUES LESS THAN (1483246800) ENGINE = InnoDB, PARTITION p201701 VALUES LESS THAN (1485925200) ENGINE = InnoDB, PARTITION p201702 VALUES LESS THAN (1488344400) ENGINE = InnoDB, PARTITION p201703 VALUES LESS THAN (1491019200) ENGINE = InnoDB, PARTITION p201704 VALUES LESS THAN (1493611200) ENGINE = InnoDB, PARTITION p201705 VALUES LESS THAN (1496289600) ENGINE = InnoDB, PARTITION p201706 VALUES LESS THAN (1498881600) ENGINE = InnoDB, PARTITION p201707 VALUES LESS THAN (1501560000) ENGINE = InnoDB, PARTITION p201708 VALUES LESS THAN (1504238400) ENGINE = InnoDB, PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 1 row in set (0.00 sec) MariaDB [db1]> CALL db1.perform_partition_maintenance('db1', 'quarterly_report_status', 3, 6, 5); +--------------------------------------------------------------------------+ | CONCAT('Dropping all partitions before: ', @last_partition_name_to_keep) | +--------------------------------------------------------------------------+ | Dropping all partitions before: p201702 | +--------------------------------------------------------------------------+ 1 row in set (0.00 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201610 | +--------------------------------------------------------+ 1 row in set (0.00 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (0.02 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (5.02 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201611 | +--------------------------------------------------------+ 1 row in set (5.02 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (5.03 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (10.03 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201612 | +--------------------------------------------------------+ 1 row in set (10.03 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (10.06 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (15.06 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201701 | +--------------------------------------------------------+ 1 row in set (15.06 sec) +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | CONCAT('Reorganizing first and second partitions. first partition date = ', @new_first_partition_date, ', second partition date = ', @second_partition_date) | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Reorganizing first and second partitions. first partition date = 2017-02-01 00:00:00, second partition date = 2017-03-01 00:00:00 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (15.08 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201709 | +--------------------------------------------------------+ 1 row in set (15.16 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201710 | +--------------------------------------------------------+ 1 row in set (15.17 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201711 | +--------------------------------------------------------+ 1 row in set (15.17 sec) Query OK, 0 rows affected (15.26 sec) MariaDB [db1]> SHOW CREATE TABLE db1.quarterly_report_status\G *************************** 1. row *************************** Table: quarterly_report_status Create Table: CREATE TABLE `quarterly_report_status` ( `report_id` int(11) NOT NULL, `report_status` varchar(20) NOT NULL, `report_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated)) (PARTITION p_first VALUES LESS THAN (1485925200) ENGINE = InnoDB, PARTITION p201702 VALUES LESS THAN (1488344400) ENGINE = InnoDB, PARTITION p201703 VALUES LESS THAN (1491019200) ENGINE = InnoDB, PARTITION p201704 VALUES LESS THAN (1493611200) ENGINE = InnoDB, PARTITION p201705 VALUES LESS THAN (1496289600) ENGINE = InnoDB, PARTITION p201706 VALUES LESS THAN (1498881600) ENGINE = InnoDB, PARTITION p201707 VALUES LESS THAN (1501560000) ENGINE = InnoDB, PARTITION p201708 VALUES LESS THAN (1504238400) ENGINE = InnoDB, PARTITION p201709 VALUES LESS THAN (1506830400) ENGINE = InnoDB, PARTITION p201710 VALUES LESS THAN (1509508800) ENGINE = InnoDB, PARTITION p201711 VALUES LESS THAN (1512104400) ENGINE = InnoDB, PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ 1 row in set (0.00 sec)
該存儲過程執行也跟咱們預期結果同樣。
應該注意的是,這些存儲過程能夠比必要時更頻繁地運行。若是在不須要添加或刪除分區時運行這些過程,則該過程將不會執行任何工做。讓咱們重置表定義,而後試一下。
MariaDB [db1]> CALL db1.perform_partition_maintenance('db1', 'quarterly_report_status', 3, 6, 5); +--------------------------------------------------------------------------+ | CONCAT('Dropping all partitions before: ', @last_partition_name_to_keep) | +--------------------------------------------------------------------------+ | Dropping all partitions before: p201702 | +--------------------------------------------------------------------------+ 1 row in set (0.00 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201610 | +--------------------------------------------------------+ 1 row in set (0.00 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (0.03 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (5.03 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201611 | +--------------------------------------------------------+ 1 row in set (5.03 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (5.06 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (10.06 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201612 | +--------------------------------------------------------+ 1 row in set (10.06 sec) +---------------------------------------------------------+ | CONCAT('Sleeping for ', p_seconds_to_sleep, ' seconds') | +---------------------------------------------------------+ | Sleeping for 5 seconds | +---------------------------------------------------------+ 1 row in set (10.08 sec) +---------------------------+ | SLEEP(p_seconds_to_sleep) | +---------------------------+ | 0 | +---------------------------+ 1 row in set (15.09 sec) +--------------------------------------------------------+ | CONCAT('Dropping partition: ', current_partition_name) | +--------------------------------------------------------+ | Dropping partition: p201701 | +--------------------------------------------------------+ 1 row in set (15.09 sec) +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | CONCAT('Reorganizing first and second partitions. first partition date = ', @new_first_partition_date, ', second partition date = ', @second_partition_date) | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Reorganizing first and second partitions. first partition date = 2017-02-01 00:00:00, second partition date = 2017-03-01 00:00:00 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (15.11 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201709 | +--------------------------------------------------------+ 1 row in set (15.18 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201710 | +--------------------------------------------------------+ 1 row in set (15.18 sec) +--------------------------------------------------------+ | CONCAT('Creating partition: ', @partition_name_to_add) | +--------------------------------------------------------+ | Creating partition: p201711 | +--------------------------------------------------------+ 1 row in set (15.18 sec) Query OK, 0 rows affected (15.28 sec) MariaDB [db1]> CALL db1.perform_partition_maintenance('db1', 'quarterly_report_status', 3, 6, 5); +--------------------------------------------------------------------------+ | CONCAT('Dropping all partitions before: ', @last_partition_name_to_keep) | +--------------------------------------------------------------------------+ | Dropping all partitions before: p201702 | +--------------------------------------------------------------------------+ 1 row in set (0.01 sec) Query OK, 0 rows affected (0.02 sec)
正如咱們從上面的輸出中看到的,這個過程第二次沒有執行任何工做。
咱們但願咱們的存儲過程每月自動運行,這樣咱們就可使用一個事件來完成這個過程。在測試這個事件以前,咱們須要作兩件事:
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | event_scheduler | OFF | +-----------------+-------+ 1 row in set (0.00 sec) MariaDB [(none)]> SET GLOBAL event_scheduler=ON; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | event_scheduler | ON | +-----------------+-------+ 1 row in set (0.00 sec)
而後,咱們能夠運行如下內容:
DROP EVENT db1.monthly_perform_partition_maintenance_event; CREATE EVENT db1.monthly_perform_partition_maintenance_event ON SCHEDULE EVERY 1 MONTH STARTS NOW() DO CALL db1.perform_partition_maintenance('db1', 'quarterly_report_status', 3, 6, 5);
然而,咱們能夠在這裏修改完善一下。每個月運行一次這個過程可能並不太理想,由於若是這個過程由於某種緣由失敗了,那麼直到下個月它可能都不會再一次執行。出於這個緣由,最好更頻繁一下去運行這個過程,好比天天一次。正如上面所提到的,只有當分區維護是必要的時候,這個過程纔會起做用,因此更頻繁地執行這個過程也不會引發任何問題。
若是咱們想天天運行一次程序,那麼事件定義就變成:
DROP EVENT db1.monthly_perform_partition_maintenance_event; CREATE EVENT db1.monthly_perform_partition_maintenance_event ON SCHEDULE EVERY 1 DAY STARTS NOW() DO CALL db1.perform_partition_maintenance('db1', 'quarterly_report_status', 3, 6, 5);
因爲存儲過程和事件的靈活性,在MariaDB中自動執行分區維護相對容易。