mysql自动分区自动清理

本文介绍了一种MySQL自动分区管理方案,通过存储过程和事件结合使用,实现tb_log表的自动分区及过期数据的自动删除,始终保持最新的30天数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 概述

mysql分区表功能特别有用,其中一个应用就是保存固定时间的数据信息,自动分区自动purge,不用担心数据量越积累越多。

比较实用的一个实现方式是表一天一个分区,保持固定天数的数据。

2. 完整的SQL

以数据库log为例,里面有一个表tb_log, 按天分区,始终保存最新的30天的数据。

存储过程sp_create_log_partition和sp_drop_log_partition用于创建和删除分区。

事件event_log_auto_partition每天执行一次,用于向前创建新的分区和删除过期的分区。

存储过程和事件结合使用就实现了tb_log数据的自动分区自动删除。

--
-- Definition for database log
--
DROP DATABASE IF EXISTS log;
CREATE DATABASE IF NOT EXISTS log
CHARACTER SET utf8
COLLATE utf8_general_ci;

-- 
-- Set default database
--
USE log;

--
-- Definition for table tb_log
--
CREATE TABLE IF NOT EXISTS tb_log (
  id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  log varchar(512) NOT NULL DEFAULT '',
  PRIMARY KEY (id, created_at)
)
ENGINE = INNODB
AUTO_INCREMENT = 1
AVG_ROW_LENGTH = 16384
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
PARTITION BY RANGE(TO_DAYS(created_at))
(
PARTITION pbasic VALUES LESS THAN (0)
);

DELIMITER $$

--
-- Definition for procedure sp_create_log_partition
--
CREATE DEFINER = 'uiadmin'@'%'
PROCEDURE sp_create_log_partition (day_value datetime, tb_name varchar(128))
BEGIN
  DECLARE par_name varchar(32);
  DECLARE par_value varchar(32);
  DECLARE _err int(1);
  DECLARE par_exist int(1);
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND SET _err = 1;
  START TRANSACTION;
    SET par_name = CONCAT('p', DATE_FORMAT(day_value, '%Y%m%d'));
    SELECT
      COUNT(1) INTO par_exist
    FROM information_schema.PARTITIONS
    WHERE TABLE_SCHEMA = 'log' AND TABLE_NAME = tb_name AND PARTITION_NAME = par_name;
    IF (par_exist = 0) THEN
      SET par_value = DATE_FORMAT(day_value, '%Y-%m-%d');
      SET @alter_sql = CONCAT('alter table ', tb_name, ' add PARTITION (PARTITION ', par_name, ' VALUES LESS THAN (TO_DAYS("', par_value, '")+1))');
      PREPARE stmt1 FROM @alter_sql;
      EXECUTE stmt1;
    END IF;
  END
  $$

--
-- Definition for procedure sp_drop_log_partition
--
CREATE DEFINER = 'uiadmin'@'%'
PROCEDURE sp_drop_log_partition (day_value datetime, tb_name varchar(128))
BEGIN
  DECLARE str_day varchar(64);
  DECLARE _err int(1);
  DECLARE done int DEFAULT 0;
  DECLARE par_name varchar(64);
  DECLARE cur_partition_name CURSOR FOR
  SELECT
    partition_name
  FROM INFORMATION_SCHEMA.PARTITIONS
  WHERE TABLE_SCHEMA = 'log' AND table_name = tb_name
  ORDER BY partition_ordinal_position;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND SET _err = 1;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
  SET str_day = DATE_FORMAT(day_value, '%Y%m%d');
  OPEN cur_partition_name;
  REPEAT
    FETCH cur_partition_name INTO par_name;
    IF (str_day > SUBSTRING(par_name, 2)) THEN
      SET @alter_sql = CONCAT('alter table ', tb_name, ' drop PARTITION ', par_name);
      PREPARE stmt1 FROM @alter_sql;
      EXECUTE stmt1;
    END IF;
  UNTIL done END REPEAT;
  CLOSE cur_partition_name;
END
$$

--
-- Definition for event event_log_auto_partition
--
CREATE
DEFINER = 'uiadmin'@'%'
EVENT event_log_auto_partition
ON SCHEDULE EVERY '1' DAY
STARTS '1972-01-01 00:00:00'
ON COMPLETION PRESERVE
DO
BEGIN
  CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL - 3 DAY), 'tb_log');
  CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL - 2 DAY), 'tb_log');
  CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL - 1 DAY), 'tb_log');
  CALL sp_create_log_partition(NOW(), 'tb_log');
  CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL 1 DAY), 'tb_log');
  CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL 2 DAY), 'tb_log');
  CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL 3 DAY), 'tb_log');
  CALL sp_drop_log_partition(DATE_ADD(NOW(), INTERVAL - 30 DAY), 'tb_log');

END
$$

--
-- Create partitions based on current time
--
CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL - 3 DAY), 'tb_log')$$
CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL - 2 DAY), 'tb_log')$$
CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL - 1 DAY), 'tb_log')$$
CALL sp_create_log_partition(NOW(), 'tb_log')$$
CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL 1 DAY), 'tb_log')$$
CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL 2 DAY), 'tb_log')$$
CALL sp_create_log_partition(DATE_ADD(NOW(), INTERVAL 3 DAY), 'tb_log')$$

DELIMITER ;

3. 查看分区

select TABLE_SCHEMA, TABLE_NAME,PARTITION_NAME from INFORMATION_SCHEMA.PARTITIONS where TABLE_SCHEMA='log' and table_name='tb_log';

在磁盘上一个分区表现为一个文件,所以删除操作会很快完成的。




<think>嗯,用户想了解如何在MySQL中配置自动清理二进制日志文件。这是个很实际的数据库管理问题,用户可能是DBA或者运维人员,需要优化服务器存储空间。从用户提问的精准度来看,ta应该对MySQL有基础了解,但可能不熟悉日志管理的具体操作。 我注意到引用材料里给出了几种解决方案:永久禁用日志(引用3)、手动清理命令(引用2、4)、以及自动清理配置(引用1、5)。其中用户明确要求的是自动清理方案,所以重点要放在expire_logs_days和binlog_expire_logs_seconds这两个系统变量上。 用户可能没意识到的是,自动清理存在两个版本的控制参数——传统的按天数和新的按秒数。这需要特别说明,因为MySQL 8.0.14之后推荐使用更精确的秒级控制。另外引用1的甘特图显示配置后需要重启服务,但实际在MySQL 8.0+可以通过SET PERSIST动态生效,这点需要补充说明。 考虑到用户可能的环境差异,应该同时给出配置文件修改和命令行修改两种方式。安全方面也要提醒,自动清理会影响时间点恢复能力,这个风险点引用5提到过但没展开。最后用饼图说明磁盘空间占比很直观,但具体数值75%只是示例,实际要强调用SHOW BINARY LOGS命令查看真实数据。 用户上次问的是手动清理,这次转向自动化配置,说明ta可能在寻求运维效率提升。或许ta的团队正在建立标准化运维流程?所以回答里要包含具体的操作命令和验证步骤,方便直接落地实施。</think>以下是MySQL配置自动清理二进制日志文件的完整步骤及注意事项: ### 📌 一、核心配置参数 1. **按天数清理**(传统方式) 在MySQL配置文件 `my.cnf` 或 `my.ini` 中添加: ```ini [mysqld] expire_logs_days = 7 # 保留最近7天的日志 ``` > ⚠️ 注意:MySQL 8.0+ 仍兼容此参数,但推荐使用新的秒级参数 2. **按秒数清理**(MySQL 8.0.14+ 推荐) ```ini [mysqld] binlog_expire_logs_seconds = 604800 # 保留7天(7×24×3600=604800秒) ``` ### 🔧 二、配置步骤 1. **修改配置文件** ```bash sudo vim /etc/my.cnf # Linux示例路径 ``` 在 `[mysqld]` 段落下添加上述任一参数 2. **动态生效(无需重启)** 登录MySQL执行: ```sql SET PERSIST binlog_expire_logs_seconds = 604800; -- MySQL 8.0+ -- 或 SET GLOBAL expire_logs_days = 7; -- 旧版本 ``` 3. **重启MySQL服务**(若需配置文件完全生效) ```bash sudo systemctl restart mysqld ``` ### 🔍 三、验证配置 ```sql SHOW VARIABLES LIKE 'binlog_expire_logs_seconds'; -- 新版本 -- 或 SHOW VARIABLES LIKE 'expire_logs_days'; -- 旧版本 ``` 输出应显示设定的值: ``` +----------------------------+---------+ | Variable_name | Value | +----------------------------+---------+ | binlog_expire_logs_seconds | 604800 | +----------------------------+---------+ ``` ### ⚠️ 四、注意事项 1. **清理触发时机** - 日志文件超过保留时间后,在**下次binlog轮换时**自动删除(如执行 `FLUSH LOGS` 或重启服务) - 或当**binlog文件大小超过 max_binlog_size** 时触发轮换 2. **空间释放逻辑** 删除的仅是**已完成写入的旧日志文件**,当前活跃文件(正在写入的)不会被清除 3. **主从复制环境** 若存在从库复制延迟,需确保 `expire_logs_days` 大于复制延迟时间,否则可能导致复制中断 4. **手动立即清理** 临时释放空间可使用命令: ```sql PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY; -- 立即删除7天前日志 ``` ### 📊 五、监控建议 定期检查日志状态: ```sql SHOW BINARY LOGS; -- 查看现有日志文件及大小 ``` 配合监控磁盘空间使用(如Linux的 `df -h`),确保日志存储分区充足。 > 💡 **最佳实践**:生产环境建议保留至少7-14天的二进制日志,用于故障恢复和审计。根据引用[5],定期清理可显著提升数据库性能并释放磁盘空间[^5]。 --- ### 🔍 相关问题 1. **MySQL二进制日志突然暴增可能是什么原因?** - 排查方向:大量数据变更操作、未提交的大事务、复制延迟导致日志积压 2. **如何安全清理正在被复制的二进制日志?** - 需检查从库复制进度:`SHOW SLAVE STATUS` 确认 `Relay_Master_Log_File` 位置 - 使用 `PURGE BINARY LOGS TO 'mysql-bin.xxxxxx'` 保留从库所需的日志点 3. **二进制日志自动清理失效的常见原因?** - 配置文件未正确加载 - 存在未释放的旧事务 - 磁盘空间不足导致日志轮换失败 4. **除了时间策略,能否按日志大小自动清理?** - MySQL原生不支持按总大小清理 - 可通过脚本监控磁盘使用率,结合 `PURGE BINARY LOGS` 实现定制清理 > 参考文档: > [^2]: MySQL二进制日志配置与清理方法 > [^5]: 二进制日志维护对数据库性能的影响原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值