MySQL HeatWave 数据库日常维护:别只顾扩容,先做好"家务"

2026-05-23 23 预计阅读时间:1 分钟
来源:blogs.oracle.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:10 分钟

业务在涨,数据在涨,团队的第一反应往往是——加节点、扩存储。但 MySQL HeatWave 环境里最容易被忽视的问题,恰恰不是资源不够,而是"家务没做"。长期不清理的冗余数据、过期的二进制日志、膨胀的临时表空间,会悄悄拖慢备份、放大复制延迟、拉低查询性能,最后账单也跟着涨。

这篇文章把 HeatWave 里最值得定期执行的几项维护操作梳理出来,并给出可以直接跑的检查和清理脚本。

冗余数据才是存储膨胀的头号元凶

HeatWave 的存储按用量计费,一张没清理过的日志表、一堆过期的测试数据,可能占了总容量的 30% 以上却不产生任何业务价值。常见的冗余来源:

  • 业务日志表:操作日志、访问记录,写入量大但查询需求随时间递减。
  • 软删除残留:用 is_deleted=1 标记删除,数据行仍在物理存储中。
  • 临时/中间表:ETL 流程跑完后没清理的 staging 表。

先量化问题——跑一轮存储审计:

-- 按表大小排序,找出 Top 20 占空间的表
SELECT
    table_schema,
    table_name,
    ROUND(data_length / 1024 / 1024, 2) AS data_mb,
    ROUND(index_length / 1024 / 1024, 2) AS index_mb,
    ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb,
    table_rows
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
ORDER BY (data_length + index_length) DESC
LIMIT 20;

结果出来后,对大表逐个判断:是否还有活跃查询?是否可以归档或分区裁剪?对确认无业务价值的表,直接删除比 DELETE 更高效,因为 DROP TABLE 立即释放空间,而大批量 DELETE 会留下碎片。

-- 归档后删除:先备份再 DROP,避免误删
CREATE TABLE archive.operation_log_2023 AS
SELECT * FROM operation_log WHERE created_at < '2024-01-01';

-- 确认归档数据无误后再删除原表对应分区或整表
ALTER TABLE operation_log DROP PARTITION p2023;

如果表没有分区,用分批删除 + OPTIMIZE TABLE 组合来回收空间:

-- 分批删除,避免长事务锁表
DELETE FROM operation_log WHERE created_at < '2024-01-01' LIMIT 10000;
-- 重复执行直到 affected_rows = 0

-- 删除完成后回收碎片
OPTIMIZE TABLE operation_log;

注意OPTIMIZE TABLE 在线上执行时会锁表,建议在低峰期或维护窗口操作,HeatWave 的 OCI 控制台可以查看当前连接数来选择时机。

二进制日志和备份时间的隐性关联

二进制日志(binlog)是复制的基石,也是时间点恢复(PITR)的依赖。但如果不设过期策略,binlog 会持续堆积,直接后果:

  • 备份镜像变大,备份耗时拉长,恢复窗口也跟着变。
  • 复制延迟风险上升——relay log 堆积在 replica 端,I/O 线程追不上。
  • 存储成本无意义增长。

检查当前 binlog 状态:

-- 查看 binlog 过期天数和当前文件列表
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW VARIABLES LIKE 'expire_logs_days';  -- 8.0 之前版本

-- 列出所有 binlog 文件及大小
SHOW BINARY LOGS;

HeatWave 在 OCI 上默认的过期策略可能偏保守。建议根据业务 PITR 需求设定合理值——大多数场景 7 天足够:

-- 设置 binlog 保留 7 天(单位为秒)
SET GLOBAL binlog_expire_logs_seconds = 604800;

-- 确认配置持久化(HeatWave 通过 OCI 配置管理持久化,也可写入 mysqld-auto.cnf)
-- 如果是用户可持久化的参数:
SET PERSIST binlog_expire_logs_seconds = 604800;

手动清理已经过期的 binlog:

-- 清理到指定编号之前的 binlog
PURGE BINARY LOGS TO 'mysql-bin.000145';

-- 或按时间清理
PURGE BINARY LOGS BEFORE '2025-01-08 00:00:00';

InnoDB 碎片与查询性能的因果链

DELETEUPDATE 在 InnoDB 里不会自动回收物理空间,页内出现大量空洞后,扫描同一张表需要读更多页,查询变慢是必然结果。碎片率高的表,即使行数不多,也可能拖垮 HeatWave 的加速查询引擎——因为加载到 HeatWave 内存列存的数据量取决于物理大小而非逻辑行数。

检测碎片程度:

-- 计算每张表的碎片率(DATA_FREE / TOTAL_SIZE)
SELECT
    table_schema,
    table_name,
    ROUND(data_free / 1024 / 1024, 2) AS free_mb,
    ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb,
    ROUND(data_free / (data_length + index_length) * 100, 2) AS fragment_pct
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
  AND data_free > 0
ORDER BY fragment_pct DESC
LIMIT 20;

碎片率超过 20% 的表值得 OPTIMIZE。但线上操作需要策略——用 pt-online-schema-change 或在 HeatWave 维护窗口执行:

# 使用 Percona Toolkit 在线重建表(不锁表)
# 需要在可以连接 HeatWave MySQL 的客户端主机上安装 pt-online-schema-change
pt-online-schema-change \
  --alter "ENGINE=InnoDB" \
  --user=admin --password=your_password \
  --host=heatwave-mysql-endpoint \
  --execute \
  D=production,t=order_line

如果环境不允许安装 Percona 工具,退回到低峰期直接 OPTIMIZE

-- 低峰期逐表执行
OPTIMIZE TABLE production.order_line;

HeatWave 列存加载也需要"打扫"

HeatWave 的加速查询依赖数据加载到内存列存(HeatWave LB)。如果源表碎片严重,加载到列存的数据体积也偏大,直接挤占内存配额,导致能同时加速的表变少。

维护要点:

  1. 源表碎片清理后再做 ALTER TABLE ... SECONDARY_LOAD,避免把膨胀数据搬进列存。
  2. 不再需要加速查询的表及时卸载
-- 卸载不再需要 HeatWave 加速的表,释放内存配额
ALTER TABLE production.archive_report SECONDARY_UNLOAD;
  1. 定期检查列存占用
-- 查看 HeatWave 加速引擎内存使用概况
SHOW GLOBAL STATUS LIKE 'Heatwave%';

一份可落地的维护清单

把上面各项串成可重复执行的维护流程,建议至少每月跑一次:

维护项 操作 频率 风险点
存储审计 Top 20 大表查询 每周
冗余数据清理 分区裁剪 / 分批 DELETE + OPTIMIZE 每月 锁表,需低峰期
Binlog 过期策略 binlog_expire_logs_seconds + PURGE 配置一次,检查每周 过短影响 PITR
碎片检测 DATA_FREE / TOTAL_SIZE 比率 每月
碎片回收 OPTIMIZE TABLE 或 pt-osc 每月(碎片率 >20%) 锁表
HeatWave 列存卸载 SECONDARY_UNLOAD 不活跃表 每季度 查询回退到 MySQL
备份耗时监控 记录每次备份 duration,环比对比 每次备份后

下面是一个可以放进 Cron 或 OCI Functions 每周跑一次的快速检查脚本:

#!/bin/bash
# heatwave_housekeeping_check.sh
# 输出存储 Top10、碎片 Top10、binlog 体积,供人工判断后续操作

MYSQL_HOST="heatwave-mysql-endpoint"
MYSQL_USER="admin"
MYSQL_PASS="your_password"

echo "===== Top 10 大表 ====="
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "
SELECT table_schema, table_name,
       ROUND((data_length+index_length)/1024/1024,2) AS total_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
ORDER BY (data_length+index_length) DESC LIMIT 10;"

echo "===== 碎片率 Top 10 ====="
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "
SELECT table_schema, table_name,
       ROUND(data_free/(data_length+index_length)*100,2) AS fragment_pct,
       ROUND(data_free/1024/1024,2) AS free_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
  AND data_length+index_length > 0
ORDER BY fragment_pct DESC LIMIT 10;"

echo "===== Binlog 文件数与总体积 ====="
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "
SHOW BINARY LOGS;" | tail -n +2 | awk '{count++; size+=$4} END {print "文件数:", count, " 总体积(MB):", size/1024/1024}'

echo "===== HeatWave 列存状态 ====="
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "
SHOW GLOBAL STATUS LIKE 'Heatwave%';"

跑完之后把输出贴进团队文档,标记需要操作的项目,下一轮维护窗口逐项执行。

写在最后

扩容是显性投入,维护是隐性收益。HeatWave 的计费模型让"存储浪费"直接变成账单上的数字,而碎片和冗余对查询性能的侵蚀更隐蔽——等到用户反馈慢查询时,往往已经积攒了几个月的问题。

建议把存储审计和碎片检测纳入每周例行,Binlog 策略设好就几乎不用再管,列存卸载每季度评估一次。维护本身不复杂,难的是养成习惯。


相关推荐