nos*_*nos 12 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 RANGE (calendar_id)(
PARTITION p20091024 VALUES LESS THAN (20091024) ,
PARTITION p20091025 VALUES LESS THAN (20091025));
Run Code Online (Sandbox Code Playgroud)
我可以以某种方式使用mysql调度程序自动添加一个新的分区(提前2天) - 我正在寻找一个例子,每天都会添加一个新的分区 - 它会运行像
alter table Calls add partition (partition p20091026 values less than(20091026));
Run Code Online (Sandbox Code Playgroud)
在计划任务运行时构建p20091026/20091026,从现在+ 2天获取值.(或者我最好通过cron编写脚本吗?)
Jus*_*ant 28
是的,你可以这样做.
请注意,默认情况下调度程序不处于活动状态(请参阅事件调度程序配置),因此它不是零风险选项.例如,如果您的运营团队将您的应用迁移到新服务器,但忘记启用调度程序,那么您的应用就会受到影响.还需要特殊权限,这可能需要在新服务器上进行设置.
我的建议:首先,创建一个存储过程(请参阅下面的代码示例),它处理定期分区维护:如果表太大,则删除旧分区,并添加足够的新分区(例如1周),以便即使维护过程不是'运行一段时间,你的应用程序不会死.
然后冗余地调度对该存储过程的调用.使用MySQL调度程序,使用cron作业,并使用您喜欢的任何其他方式.然后,如果一个调度程序不工作,另一个可以调整松弛.如果正确设计了sproc,如果不需要做任何操作,执行no-op应该很便宜.您甚至可能希望从应用程序中调用它,例如,在生成长时间运行的报告时作为第一个语句,或者作为每日ETL过程的一部分(如果有的话).我的观点是,计划任务的致命弱点是确保调度程序实际工作 - 所以在这里考虑冗余.
只要确保不要同时安排所有电话,这样他们就不会互相踩!:-)
下面是维护过程可能看起来像的代码示例 - 首先修剪旧分区,然后添加新分区.我留下了错误检查并防止多个同时执行作为读者的exerise.
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 ;
Run Code Online (Sandbox Code Playgroud)
BTW,分区维护(确保提前创建新分区,修剪旧分区等),恕我直言,对自动化至关重要.我个人看到一个大型企业数据仓库停运了一天,因为最初创建了一年的分区,但没有人记得在明年到来之后创建更多分区.所以你在这里考虑自动化是非常好的 - 这对你正在进行的项目来说是个好兆头.:-)
Justin的优秀解决方案.我把他的代码作为我当前项目的起点,并想提一下我实现它时出现的一些事情.
您运行此表的现有分区结构不应包含MAXVALUE类型分区 - 所有分区必须由文字日期分隔.这是因为SELECT MAX(PARTITION_DESCRIPTION)将返回'MAXVALUE',无法在下一步中转换为日期.如果你在调用程序时得到奇怪的信息,例如:'<'的非法混合排序,这可能就是问题所在.
从INFORMATION_SCHEMA表中选择分区名称时,最好添加:"AND TABLE_SCHEMA ='dbname'",因为虽然同一个表(在不同的数据库中)可以存在多个具有相同名称的分区,但它们都列出了在INFORMATION_SCHEMA表中.如果没有TABLE_SCHEMA规范,请选择例如.MAX(PARTITION_DESCRIPTION)将为每个数据库中该名称的表的每个现有分区提供最大分区名称.
在某些地方我遇到了问题,就像在Justin的解决方案中使用ALTER TABLE xxx ADD PARTITION一样,我认为分区名称(yyyymmdd)的相同格式被用作预期yyyy-mm-dd的分区分隔符(v5.6.2).
默认行为是仅在将来根据需要添加分区.如果要为过去创建分区,则需要首先为早于所需的最旧分区的日期设置分区.例如.如果您要保留过去30天的数据,请先为35天前添加分区,然后再运行该过程.当然,在空桌上这样做可能是可行的,但我认为值得一提.
为了在4中创建所需的过去/未来分区范围,您最初需要运行该过程两次.对于上面的示例,第一次运行将创建-35天的分区以及必要的未来分区.然后第二次运行将在-35和-30之间修剪分区.
这是我目前正在使用的内容.我添加了一些参数,使其从调用者的角度来看更加灵活.您可以指定数据库,表,当前日期以及过去和将来要保留的分区数.
我还更改了分区的命名,以便名为p20110527的分区代表从2011-5-27 00:00 开始的那一天,而不是当时结束的那一天.
仍然没有错误检查或防止同时执行:-)
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 ;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11003 次 |
| 最近记录: |