MySQL可以从事件调度器创建新分区吗
我有一张像这样的桌子:MySQL可以从事件调度器创建新分区吗,mysql,partitioning,Mysql,Partitioning,我有一张像这样的桌子: CREATE TABLE `Calls` ( `calendar_id` int(11) NOT NULL, `db_date` timestamp NOT NULL, `cgn` varchar(32) DEFAULT NULL, `cpn` varchar(32) DEFAULT NULL, PRIMARY KEY (`calendar_id`), KEY `db_date_idx` (`db_date`) ) PARTITION BY R
CREATE TABLE `Calls` (
`calendar_id` int(11) NOT NULL,
`db_date` timestamp NOT NULL,
`cgn` varchar(32) DEFAULT NULL,
`cpn` varchar(32) DEFAULT NULL,
PRIMARY KEY (`calendar_id`),
KEY `db_date_idx` (`db_date`)
)
PARTITION BY RANGE (calendar_id)(
PARTITION p20091024 VALUES LESS THAN (20091024) ,
PARTITION p20091025 VALUES LESS THAN (20091025));
我可以使用mysql调度器提前2天自动添加一个新分区吗?我正在寻找一个示例,它可以每天添加一个新分区,运行如下
alter table Calls add partition (partition p20091026 values less than(20091026));
其中,p20091026/20091026是在计划任务运行时构造的,从now+2天导出值。或者我更适合通过cron编写脚本?是的,您可以这样做 请注意,计划程序在默认情况下不处于活动状态,因此它不是零风险选项。例如,如果您的操作团队将您的应用程序迁移到新服务器,但忘记启用调度程序,则您的应用程序将被关闭。还需要特殊权限,这可能需要在新服务器上设置 我的建议:首先,创建一个存储过程(参见下面的代码示例),该过程处理定期分区维护:如果表太大,则删除旧分区,并添加足够的新分区(例如1周),以便即使维护过程暂时不运行,您的应用程序也不会死掉 然后冗余地调度对该存储过程的调用。使用MySQL调度程序,使用cron作业,以及使用任何其他您喜欢的方式。然后,如果一个调度器不工作,另一个调度器可以处理空闲时间。如果正确地设计存储过程,如果不需要执行任何操作,那么执行no-op应该是便宜的。您甚至可能希望从应用程序调用它,例如,作为生成长时间运行的报告时的第一条语句,或者作为日常ETL过程的一部分(如果有)。我的观点是,计划任务的致命弱点是确保调度器实际工作——因此请考虑冗余 只需确保不要同时安排所有通话,这样他们就不会互相踩踏了!:- 下面是一个代码示例,说明您的维护过程可能是什么样子的-首先它修剪旧分区,然后添加新分区。我将错误检查和防止多个同时执行作为读者的练习
DELIMITER $$
DROP PROCEDURE IF EXISTS `test`.`UpdatePartitions` $$
CREATE PROCEDURE `test`.`UpdatePartitions` ()
BEGIN
DECLARE maxpart_date date;
DECLARE partition_count int;
DECLARE minpart date;
DECLARE droppart_sql date;
DECLARE newpart_date date;
DECLARE newpart_sql varchar(500);
SELECT COUNT(*)
INTO partition_count
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test';
-- first, deal with pruning old partitions
-- TODO: set your desired # of partitions below, or make it parameterizable
WHILE (partition_count > 1000)
DO
-- optionally, do something here to deal with the parition you're dropping, e.g.
-- copy the data into an archive table
SELECT MIN(PARTITION_DESCRIPTION)
INTO minpart
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test';
SET @sql := CONCAT('ALTER TABLE Calls DROP PARTITION p'
, CAST((minpart+0) as char(8))
, ';');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT COUNT(*)
INTO partition_count
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test';
END WHILE;
SELECT MAX(PARTITION_DESCRIPTION)
INTO maxpart_date
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test';
-- create enough partitions for at least the next week
WHILE (maxpart_date < CURDATE() + INTERVAL 7 DAY)
DO
SET newpart_date := maxpart_date + INTERVAL 1 DAY;
SET @sql := CONCAT('ALTER TABLE Calls ADD PARTITION (PARTITION p'
, CAST((newpart_date+0) as char(8))
, ' values less than('
, CAST((newpart_date+0) as char(8))
, '));');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT MAX(PARTITION_DESCRIPTION)
INTO maxpart_date
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test';
END WHILE;
END $$
DELIMITER ;
顺便说一句,分区维护——确保提前创建新分区、修剪旧分区等等——对于自动化来说至关重要。我个人看到一个大型企业数据仓库宕机一天,因为一年的分区一开始就被填满了,但是没有人记得在下一年到来时创建更多的分区。因此,您在这里考虑自动化非常好——这对您正在进行的项目是个好兆头- 贾斯汀提供的绝佳解决方案。我将他的代码作为我当前项目的起点,并想提及在我实现它时出现的一些事情
运行此操作的表中的现有分区结构不应包括MAXVALUE类型的分区-所有分区都必须由文字日期分隔。这是因为SELECT MAXPARTITION_DESCRIPTION将返回“MAXVALUE”,该值在下一步中无法转换为日期。如果在调用过程时收到一条奇怪的消息,比如:在更改表时,非法混合了“的排序规则,为什么不定义要修改的分区或缺少某些内容?”。例如,它如何知道正在将分区添加到Calendar_Id,或者您只能有一种类型的分区,并且由于分区已经创建,所以默认为Calendar_id@shahmir-上面的代码不是修改分区,而是删除一个旧分区并添加一个新分区。每个表只有一个分区方案。原始海报的问题显示分区发生在calendar_id上。每个表最多允许1024个分区,因此此解决方案将在3年内用完分区。日常分区可以提高性能的情况将非常罕见。。。如果你真的坚持这样做,你可能不需要每天创建一个新的分区,看,如果你不确定最大值是多少,我会在那里留下一个MAXVALUE分区。否则,任何值大于最大分区值的插入都将失败,因为MySQL没有可以放入的分区。当您尝试选择MAXPARTITION\u DESCRIPTION时,只需在其中添加PARTITION\u DESCRIPTION“MAXVALUE”。您必须更改ADD分区以相应地重新组织分区。
DELIMITER $$
DROP PROCEDURE IF EXISTS UpdatePartitions $$
-- Procedure to delete old partitions and create new ones based on a given date.
-- partitions older than (today_date - days_past) will be dropped
-- enough new partitions will be made to cover until (today_date + days_future)
CREATE PROCEDURE UpdatePartitions (dbname TEXT, tblname TEXT, today_date DATE, days_past INT, days_future INT)
BEGIN
DECLARE maxpart_date date;
DECLARE partition_count int;
DECLARE minpart date;
DECLARE droppart_sql date;
DECLARE newpart_date date;
DECLARE newpart_sql varchar(500);
SELECT COUNT(*)
INTO partition_count
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME=tblname
AND TABLE_SCHEMA=dbname;
-- SELECT partition_count;
-- first, deal with pruning old partitions
WHILE (partition_count > days_past + days_future)
DO
-- optionally, do something here to deal with the parition you're dropping, e.g.
-- copy the data into an archive table
SELECT STR_TO_DATE(MIN(PARTITION_DESCRIPTION), '''%Y-%m-%d''')
INTO minpart
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME=tblname
AND TABLE_SCHEMA=dbname;
-- SELECT minpart;
SET @sql := CONCAT('ALTER TABLE '
, tblname
, ' DROP PARTITION p'
, CAST(((minpart - INTERVAL 1 DAY)+0) as char(8))
, ';');
-- SELECT @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT COUNT(*)
INTO partition_count
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME=tblname
AND TABLE_SCHEMA=dbname;
-- SELECT partition_count;
END WHILE;
SELECT STR_TO_DATE(MAX(PARTITION_DESCRIPTION), '''%Y-%m-%d''')
INTO maxpart_date
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME=tblname
AND TABLE_SCHEMA=dbname;
-- select maxpart_date;
-- create enough partitions for at least the next days_future days
WHILE (maxpart_date < today_date + INTERVAL days_future DAY)
DO
-- select 'here1';
SET newpart_date := maxpart_date + INTERVAL 1 DAY;
SET @sql := CONCAT('ALTER TABLE '
, tblname
, ' ADD PARTITION (PARTITION p'
, CAST(((newpart_date - INTERVAL 1 DAY)+0) as char(8))
, ' VALUES LESS THAN ('''
, newpart_date
, '''));');
-- SELECT @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT STR_TO_DATE(MAX(PARTITION_DESCRIPTION), '''%Y-%m-%d''')
INTO maxpart_date
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME=tblname
AND TABLE_SCHEMA=dbname;
SET maxpart_date := newpart_date;
END WHILE;
END $$
DELIMITER ;