-- ============================================================ -- 自动分区与日志清理(幂等) -- 1) 分区管理表 log_partition_tracker -- 2) 存储过程 sp_ensure_partitions -- 3) 存储过程 sp_check_partitions -- 4) MariaDB 事件 ev_ensure_partitions -- 注意:本脚本设计为幂等,重复执行不会重复创建分区 -- ============================================================ USE cnc_log; -- 1. 分区追踪表 CREATE TABLE IF NOT EXISTS log_partition_tracker ( table_name VARCHAR(100) NOT NULL, partition_name VARCHAR(50) NOT NULL, partition_value VARCHAR(30) NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (table_name, partition_name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='分区管理追踪表'; -- 2. 自动分区存储过程 DELIMITER $$ DROP PROCEDURE IF EXISTS sp_ensure_partitions$$ CREATE PROCEDURE sp_ensure_partitions() BEGIN -- 当前月的第一天 SET @base := DATE_FORMAT(CURDATE(), '%Y-%m-01'); SET @d1 := DATE_ADD(@base, INTERVAL 1 MONTH); SET @d2 := DATE_ADD(@base, INTERVAL 2 MONTH); SET @p1 := CONCAT('p', DATE_FORMAT(@d1, '%Y%m')); SET @p2 := CONCAT('p', DATE_FORMAT(@d2, '%Y%m')); -- 对 log_collect_analysis 表分区 IF NOT EXISTS (SELECT 1 FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_analysis' AND PARTITION_NAME = @p1) THEN SET @dead1 := DATE_FORMAT(@d1, '%Y-%m-01'); SET @sql := CONCAT('ALTER TABLE cnc_log.log_collect_analysis ADD PARTITION (PARTITION ', @p1, ' VALUES LESS THAN (TO_DAYS(', '''', @dead1, '''', '))'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; INSERT IGNORE INTO log_partition_tracker(table_name, partition_name, partition_value) VALUES ('log_collect_analysis', @p1, @dead1); END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_analysis' AND PARTITION_NAME = @p2) THEN SET @dead2 := DATE_FORMAT(@d2, '%Y-%m-01'); SET @sql := CONCAT('ALTER TABLE cnc_log.log_collect_analysis ADD PARTITION (PARTITION ', @p2, ' VALUES LESS THAN (TO_DAYS(', '''', @dead2, '''', '))'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; INSERT IGNORE INTO log_partition_tracker(table_name, partition_name, partition_value) VALUES ('log_collect_analysis', @p2, @dead2); END IF; -- 对 log_collect_cycle 表分区 IF NOT EXISTS (SELECT 1 FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_cycle' AND PARTITION_NAME = @p1) THEN SET @dead1 := DATE_FORMAT(@d1, '%Y-%m-01'); SET @sql := CONCAT('ALTER TABLE cnc_log.log_collect_cycle ADD PARTITION (PARTITION ', @p1, ' VALUES LESS THAN (TO_DAYS(', '''', @dead1, '''', '))'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; INSERT IGNORE INTO log_partition_tracker(table_name, partition_name, partition_value) VALUES ('log_collect_cycle', @p1, @dead1); END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_cycle' AND PARTITION_NAME = @p2) THEN SET @dead2 := DATE_FORMAT(@d2, '%Y-%m-01'); SET @sql := CONCAT('ALTER TABLE cnc_log.log_collect_cycle ADD PARTITION (PARTITION ', @p2, ' VALUES LESS THAN (TO_DAYS(', '''', @dead2, '''', '))'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; INSERT IGNORE INTO log_partition_tracker(table_name, partition_name, partition_value) VALUES ('log_collect_cycle', @p2, @dead2); END IF; END$$ DELIMITER ; -- 3. 分区检查存储过程 DELIMITER $$ DROP PROCEDURE IF EXISTS sp_check_partitions$$ CREATE PROCEDURE sp_check_partitions() BEGIN -- 计算未来两月分区名是否存在 SET @base := DATE_FORMAT(CURDATE(), '%Y-%m-01'); SET @d1 := DATE_ADD(@base, INTERVAL 1 MONTH); SET @d2 := DATE_ADD(@base, INTERVAL 2 MONTH); SET @p1 := CONCAT('p', DATE_FORMAT(@d1, '%Y%m')); SET @p2 := CONCAT('p', DATE_FORMAT(@d2, '%Y%m')); SET @need := 0; IF (SELECT COUNT(*) FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_analysis' AND PARTITION_NAME = @p1) = 0 THEN SET @need = 1; END IF; IF (SELECT COUNT(*) FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_cycle' AND PARTITION_NAME = @p1) = 0 THEN SET @need = 1; END IF; IF (SELECT COUNT(*) FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_analysis' AND PARTITION_NAME = @p2) = 0 THEN SET @need = 1; END IF; IF (SELECT COUNT(*) FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_cycle' AND PARTITION_NAME = @p2) = 0 THEN SET @need = 1; END IF; IF @need = 1 THEN CALL sp_ensure_partitions(); END IF; SELECT @need AS need_partition_creation; END$$ DELIMITER ; -- 4. MariaDB 事件:每月1日凌晨2:00执行 sp_check_partitions SET GLOBAL event_scheduler = ON; DROP EVENT IF EXISTS ev_ensure_partitions; CREATE EVENT IF NOT EXISTS ev_ensure_partitions ON SCHEDULE EVERY 1 MONTH STARTS TIMESTAMP '2026-06-01 02:00:00' DO CALL sp_check_partitions();