You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
haoliang-net/database/sqls/04-auto-partition-and-clean...

109 lines
5.3 KiB
SQL

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

-- ============================================================
-- 自动分区与日志清理(幂等)
-- 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();