MySQL数据库日常维护:这6件事必须定期做

MySQL数据库日常维护:这6件事必须定期做

你的数据库跑了半年。一开始很快,现在越来越慢。你没动过它,没改过配置,没加过数据。为什么会慢?因为数据库不是“装好就不用管”。它会积累碎片,会留下没用过的索引,会写越来越多的日志,会存着你忘了删的历史数据。不维护,它就会慢慢变慢,直到你受不了。

今天讲6件定期要做的事。每月花半小时,让数据库一直保持健康。


先看一个数据

某DBA团队统计,超过70%的数据库性能下降,不是硬件问题,是缺乏日常维护。碎片堆积、索引失效、日志膨胀。这些问题不修,硬件升级了也没用。每月半小时,能避免90%的“数据库莫名其妙慢”。


第一件:查看表大小,找到增长过快的表

不是所有表都需要维护。先找出谁在“变胖”。

sql

SELECT 
    table_schema AS '数据库',
    table_name AS '表名',
    round(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)'
FROM information_schema.tables
ORDER BY (data_length + index_length) DESC
LIMIT 10;

输出最大的是日志表、流水表。这些表通常会无限增长,需要定期清理或归档。如果某张表一个月涨了20%,要关注。可能代码有bug写入了不该写的数据,或者业务增长超预期,该考虑分表了。

做多久:1分钟。每月看一次。


第二件:清理binlog(二进制日志)

binlog记录所有数据变更,用于主从复制和恢复。不清理会一直占用磁盘,直到写满。很多数据库磁盘爆满,元凶是binlog。

查看binlog占用:

sql

SHOW BINARY LOGS;

设置自动清理:

sql

-- 保留最近7天的binlog
SET GLOBAL expire_logs_days = 7;

在配置文件/etc/my.cnf里永久设置:

ini

expire_logs_days = 7
max_binlog_size = 100M

重启MySQL后永久生效。如果是主库,不要设太短,确认从库已经跟上了再删。一般保留3-7天。

做多久:2分钟。每月检查一次设置。


第三件:优化表(清理碎片)

频繁增删改的表,会产生碎片。文件变大了,但实际数据没那么多。碎片让查询变慢,因为要扫描更多无效空间。

sql

OPTIMIZE TABLE orders;

InnoDB表执行时会重建表,释放碎片空间,期间会锁表。在业务低峰期(凌晨)执行。查看哪些表碎片多:

sql

SELECT 
    table_name,
    round(data_free / 1024 / 1024, 2) AS '碎片(MB)'
FROM information_schema.tables
WHERE table_schema = 'your_database'
ORDER BY data_free DESC;

data_free是碎片大小。大于100MB的表值得优化。不要对所有表执行OPTIMIZE,只挑碎片大的。

做多久:大表可能几分钟到几十分钟。每月或每季度一次,低峰期做。


第四件:检查慢查询日志

慢查询日志记录执行超过阈值的SQL。不主动看,可能你的数据库每天有几千条慢查询,你完全不知道。

开启慢查询日志(永久配置):

ini

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1

分析慢查询:

bash

# 用mysqldumpslow
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 或用pt-query-digest(推荐)
pt-query-digest /var/log/mysql/slow.log

看最耗时的SQL,加索引或改代码。

做多久:每月分析一次,10分钟。


第五件:检查索引使用情况

加了索引,未必在用。没用到的索引浪费磁盘空间,还拖慢写入。

查看未使用的索引:

sql

SELECT 
    t.table_schema,
    t.table_name,
    index_name
FROM information_schema.statistics s
JOIN information_schema.tables t ON s.table_schema = t.table_schema AND s.table_name = t.table_name
WHERE s.table_schema NOT IN ('mysql', 'information_schema', 'performance_schema')
AND t.table_type = 'BASE TABLE'
AND index_name NOT IN (
    SELECT DISTINCT index_name FROM performance_schema.table_io_waits_summary_by_index_usage
    WHERE index_name IS NOT NULL
);

输出是完全没有被查询使用过的索引。确认无用后删除:

sql

DROP INDEX unused_index_name ON table_name;

注意:刚建不久的索引可能还没有统计信息,等一段时间再看。

做多久:每季度一次。


第六件:验证备份可恢复

你有备份脚本,每天跑。但备份文件是好的吗?能恢复吗?半年没测过。真出事时可能恢复不了。

每月做一次恢复测试:拿一个最近的备份文件,恢复到测试环境,启动数据库,跑几条查询验证数据正确性。

自动验证脚本思路

  1. 从备份目录取最新的备份文件
  2. 恢复到临时数据库(Docker一键起)
  3. 执行SELECT COUNT(*) FROM core_tables,对比前几天记录
  4. 数据量差异过大则告警

做多久:每月一次,15分钟。


维护频率建议

任务频率耗时
查看表大小每月1分钟
清理binlog每月检查设置2分钟
优化表每季度低峰期做
慢查询分析每月10分钟
检查未使用索引每季度5分钟
验证备份恢复每月15分钟

真实案例

一个电商数据库,跑了两年没维护。某天突然慢到无法下单。检查发现:binlog没设置自动清理,占满磁盘,数据库只读。日志表1.2TB,碎片占300MB。未使用的索引有8个。清理后,查询速度恢复,磁盘空间释放40%。

运维说:“我以为数据库不会变慢。它只是慢得很慢,你没发现。”


最后一句

数据库不是你不管它就不会出问题。它会慢慢变胖、变碎、变慢。

今天去检查你的数据库:表大小谁最大?binlog清理设了吗?慢查询日志有吗?备份能恢复吗?把这6件事写进日历,每月固定时间做一遍。数据库会保持健康,你也会少很多半夜被叫醒的机会。保养一次,安稳一月。

知识库

服务器密码管理:如何设置强密码并安全存储

2026-6-12 16:08:37

知识库

云厂商账单陷阱:这些隐藏费用你中招了吗?

2026-6-15 18:20:42

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧