|
|
-- ============================================================
|
|
|
-- 日志表按月分区统一管理(幂等迁移脚本)
|
|
|
-- 创建时间:2026-05-06
|
|
|
-- 说明:确保 log_collect_raw、log_collect_analysis、log_collect_cycle
|
|
|
-- 三张日志表均按月分区,并统一存储过程管理
|
|
|
-- 执行前提:USE cnc_log; 已执行 01-init-schema.sql 和 03-collect-analysis-tables.sql
|
|
|
-- ============================================================
|
|
|
|
|
|
USE cnc_log;
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 1. log_collect_raw 按月分区
|
|
|
-- 该表在 01-init-schema.sql 中已定义分区,此处确认分区存在
|
|
|
-- 分区键:request_time
|
|
|
-- ============================================================
|
|
|
-- 检查是否已有分区,若无则重建(幂等)
|
|
|
SET @has_partition := (SELECT COUNT(*) FROM information_schema.PARTITIONS
|
|
|
WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_raw' AND PARTITION_NAME IS NOT NULL);
|
|
|
|
|
|
-- 如果表没有分区(旧表),则需要重建
|
|
|
-- 注意:如果表已有分区(从DDL创建),此步骤会跳过
|
|
|
SET @sql_rebuild := IF(@has_partition = 0,
|
|
|
'ALTER TABLE cnc_log.log_collect_raw PARTITION BY RANGE (TO_DAYS(request_time)) (
|
|
|
PARTITION p202604 VALUES LESS THAN (TO_DAYS(''2026-05-01'')),
|
|
|
PARTITION p202605 VALUES LESS THAN (TO_DAYS(''2026-06-01'')),
|
|
|
PARTITION p202606 VALUES LESS THAN (TO_DAYS(''2026-07-01'')),
|
|
|
PARTITION p202607 VALUES LESS THAN (TO_DAYS(''2026-08-01'')),
|
|
|
PARTITION p_future VALUES LESS THAN MAXVALUE
|
|
|
)',
|
|
|
'SELECT ''log_collect_raw 已有分区,跳过''');
|
|
|
PREPARE stmt FROM @sql_rebuild;
|
|
|
EXECUTE stmt;
|
|
|
DEALLOCATE PREPARE stmt;
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 2. log_collect_analysis 按月分区
|
|
|
-- 该表在 03-collect-analysis-tables.sql 中已定义分区
|
|
|
-- 分区键:analysis_time
|
|
|
-- ============================================================
|
|
|
SET @has_partition_a := (SELECT COUNT(*) FROM information_schema.PARTITIONS
|
|
|
WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_analysis' AND PARTITION_NAME IS NOT NULL);
|
|
|
|
|
|
SET @sql_rebuild_a := IF(@has_partition_a = 0,
|
|
|
'ALTER TABLE cnc_log.log_collect_analysis PARTITION BY RANGE (TO_DAYS(analysis_time)) (
|
|
|
PARTITION p202605 VALUES LESS THAN (TO_DAYS(''2026-06-01'')),
|
|
|
PARTITION p202606 VALUES LESS THAN (TO_DAYS(''2026-07-01'')),
|
|
|
PARTITION p202607 VALUES LESS THAN (TO_DAYS(''2026-08-01'')),
|
|
|
PARTITION p_future VALUES LESS THAN MAXVALUE
|
|
|
)',
|
|
|
'SELECT ''log_collect_analysis 已有分区,跳过''');
|
|
|
PREPARE stmt FROM @sql_rebuild_a;
|
|
|
EXECUTE stmt;
|
|
|
DEALLOCATE PREPARE stmt;
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 3. log_collect_cycle 按月分区
|
|
|
-- 该表在 03-collect-analysis-tables.sql 中已定义分区
|
|
|
-- 分区键:cycle_time
|
|
|
-- ============================================================
|
|
|
SET @has_partition_c := (SELECT COUNT(*) FROM information_schema.PARTITIONS
|
|
|
WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_cycle' AND PARTITION_NAME IS NOT NULL);
|
|
|
|
|
|
SET @sql_rebuild_c := IF(@has_partition_c = 0,
|
|
|
'ALTER TABLE cnc_log.log_collect_cycle PARTITION BY RANGE (TO_DAYS(cycle_time)) (
|
|
|
PARTITION p202605 VALUES LESS THAN (TO_DAYS(''2026-06-01'')),
|
|
|
PARTITION p202606 VALUES LESS THAN (TO_DAYS(''2026-07-01'')),
|
|
|
PARTITION p202607 VALUES LESS THAN (TO_DAYS(''2026-08-01'')),
|
|
|
PARTITION p_future VALUES LESS THAN MAXVALUE
|
|
|
)',
|
|
|
'SELECT ''log_collect_cycle 已有分区,跳过''');
|
|
|
PREPARE stmt FROM @sql_rebuild_c;
|
|
|
EXECUTE stmt;
|
|
|
DEALLOCATE PREPARE stmt;
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 4. 更新存储过程 sp_ensure_partitions:覆盖全部3张分区表
|
|
|
-- ============================================================
|
|
|
DROP PROCEDURE IF EXISTS sp_ensure_partitions;
|
|
|
DELIMITER $$
|
|
|
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_raw(分区键:request_time)
|
|
|
-- ============================
|
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.PARTITIONS
|
|
|
WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_raw' AND PARTITION_NAME = @p1) THEN
|
|
|
SET @v1 := DATE_FORMAT(@d1, '%Y-%m-01');
|
|
|
SET @sql := CONCAT('ALTER TABLE cnc_log.log_collect_raw ADD PARTITION (PARTITION ', @p1,
|
|
|
' VALUES LESS THAN (TO_DAYS(', '''', @v1, '''', '))');
|
|
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
|
|
INSERT IGNORE INTO log_partition_tracker(table_name, partition_name, partition_value) VALUES ('log_collect_raw', @p1, @v1);
|
|
|
END IF;
|
|
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.PARTITIONS
|
|
|
WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_raw' AND PARTITION_NAME = @p2) THEN
|
|
|
SET @v2 := DATE_FORMAT(@d2, '%Y-%m-01');
|
|
|
SET @sql := CONCAT('ALTER TABLE cnc_log.log_collect_raw ADD PARTITION (PARTITION ', @p2,
|
|
|
' VALUES LESS THAN (TO_DAYS(', '''', @v2, '''', '))');
|
|
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
|
|
INSERT IGNORE INTO log_partition_tracker(table_name, partition_name, partition_value) VALUES ('log_collect_raw', @p2, @v2);
|
|
|
END IF;
|
|
|
|
|
|
-- ============================
|
|
|
-- log_collect_analysis(分区键:analysis_time)
|
|
|
-- ============================
|
|
|
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 @v1 := 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(', '''', @v1, '''', '))');
|
|
|
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, @v1);
|
|
|
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 @v2 := 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(', '''', @v2, '''', '))');
|
|
|
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, @v2);
|
|
|
END IF;
|
|
|
|
|
|
-- ============================
|
|
|
-- log_collect_cycle(分区键:cycle_time)
|
|
|
-- ============================
|
|
|
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 @v1 := 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(', '''', @v1, '''', '))');
|
|
|
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, @v1);
|
|
|
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 @v2 := 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(', '''', @v2, '''', '))');
|
|
|
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, @v2);
|
|
|
END IF;
|
|
|
END$$
|
|
|
DELIMITER ;
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 5. 更新 sp_check_partitions:覆盖全部3张分区表
|
|
|
-- ============================================================
|
|
|
DROP PROCEDURE IF EXISTS sp_check_partitions;
|
|
|
DELIMITER $$
|
|
|
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;
|
|
|
|
|
|
-- log_collect_raw
|
|
|
IF (SELECT COUNT(*) FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = 'cnc_log' AND TABLE_NAME = 'log_collect_raw' 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_raw' AND PARTITION_NAME = @p2) = 0 THEN SET @need = 1; END IF;
|
|
|
|
|
|
-- log_collect_analysis
|
|
|
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_analysis' AND PARTITION_NAME = @p2) = 0 THEN SET @need = 1; END IF;
|
|
|
|
|
|
-- log_collect_cycle
|
|
|
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_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 ;
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 6. 确保分区追踪表存在
|
|
|
-- ============================================================
|
|
|
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='分区管理追踪表';
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 7. 立即执行一次分区确保
|
|
|
-- ============================================================
|
|
|
CALL sp_ensure_partitions();
|
|
|
|
|
|
-- ============================================================
|
|
|
-- 8. 更新 MariaDB 事件:每月1日凌晨2:00执行
|
|
|
-- ============================================================
|
|
|
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(DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01 02:00:00'))
|
|
|
DO
|
|
|
CALL sp_check_partitions();
|