MySQL存储过程不支持ALTER TABLE ... PARTITION BY,仅能通过ADD/DROP PARTITION动态管理;按月自动分区需用DATE_SUB/TO_DAYS计算边界并PREPARE/EXECUTE拼接SQL,配合EVENT调度器每月触发,且须校验分区名唯一性与时区一致性。

MySQL不支持在存储过程中直接执行ALTER TABLE ... PARTITION BY
MySQL存储过程里不能用ALTER TABLE ... PARTITION BY动态重定义分区规则——这条语句不是“可预编译”的,存储过程解析阶段就会报错:ERROR 1064 (42000),提示语法错误或“This command is not supported in stored procedures”。分区方案必须在建表时确定,后续只能增删分区(ADD PARTITION / DROP PARTITION),不能改分区类型或表达式。
按月自动创建新分区的正确做法是ADD PARTITION + DATE_SUB计算边界
对已按RANGE COLUMNS(created_at)或RANGE (TO_DAYS(created_at))分区的表,每月初用存储过程新增一个分区。关键点在于:分区值必须严格递增、不能重叠、且下限要精确到日(RANGE)或日期函数返回整数(如TO_DAYS())。
- 用
DATE_SUB(NOW(), INTERVAL DAYOFMONTH(NOW()) DAY)算出本月第一天(如今天是2024-05-17 → 得2024-05-01) - 再用
TO_DAYS('2024-05-01')转成整数作为VALUES LESS THAN上限 - 拼接SQL字符串时,必须用
CONCAT()构造完整语句,再用PREPARE/EXECUTE执行 - 务必检查目标分区是否已存在,避免
ERROR 1517 (HY000):“Duplicate partition name”
示例片段:
SET @next_month = DATE_FORMAT(DATE_ADD(LAST_DAY(NOW()), INTERVAL 1 DAY), '%Y-%m-01');
SET @next_day_num = TO_DAYS(@next_month);
SET @sql = CONCAT('ALTER TABLE orders ADD PARTITION (PARTITION p_', DATE_FORMAT(@next_month, '%Y%m'), ' VALUES LESS THAN (', @next_day_num, '))');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
分区字段类型和函数选择直接影响能否按月扩展
如果分区字段是DATETIME但用了YEAR(created_at)分区,那一年只能加一次分区,无法按月;若用TO_DAYS(created_at),则每月都可加,但要注意:该函数对NULL返回NULL,而NULL会被路由到第一个分区,可能造成数据倾斜。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 推荐用
RANGE COLUMNS(created_at)(MySQL 5.5+),支持直接比较日期字面量,无需函数转换 - 对应
ADD PARTITION语句写成:PARTITION p_202406 VALUES LESS THAN ('2024-06-01') - 注意时区:服务器
time_zone设置会影响NOW()和字面量比较结果,建议统一用UTC或显式指定时区 -
INFORMATION_SCHEMA.PARTITIONS表可查现有分区名和TABLE_ROWS,用于判断是否需要新增
定时触发必须靠事件调度器(EVENT),不能只靠存储过程
存储过程只是“能干活”,但不会自己跑。必须启用event_scheduler=ON,再建一个每月1号凌晨执行的EVENT来调用该过程。
- 开启调度器:
SET GLOBAL event_scheduler = ON;(需SUPER权限) - 建事件时明确指定
ON SCHEDULE EVERY 1 MONTH STARTS '2024-06-01 00:00:00' - 事件体里只写
CALL add_monthly_partition('orders');,不要把SQL拼接逻辑塞进事件定义 - 事件默认用
SYSTEM时区,若业务用Asia/Shanghai,需在事件中先SET time_zone = '+8:00';
分区边界计算一旦出错,比如把'2024-06-01'写成'2024-06-00',会导致后续插入失败并报ERROR 1526 (HY000):“Table has no partition for value”。这个细节几乎每次手动维护都会漏掉。










