直接查 information_schema 表慢且不准,因 MySQL 8.0+ 动态生成元数据、5.7 及更早依赖表锁,且 DATA_LENGTH 等字段未 ANALYZE TABLE 时严重滞后。
为什么直接查
表会慢且不准
很多同学一上来就写
,结果发现执行要十几秒,甚至超时。这不是因为数据量大,而是
在 MySQL 8.0+ 默认是基于内存临时表动态生成的,每次查询都会触发元数据重载;5.7 及更早版本则依赖表锁,高并发下容易阻塞。更关键的是,某些字段(比如
、
)在未执行
前可能严重滞后,导致空间统计失真。
实操建议:
对核心库,改用
获取近期访问热度,比静态大小更有业务意义
需要准确空间指标时,先对目标表执行
(注意:该操作会加 MDL 读锁,避开业务高峰)
避免在存储过程中遍历全部
记录——用
过滤系统库
如何让存储过程安全地遍历所有用户库并采集指标
硬编码库名不可扩展,用游标动态查又容易因权限不足或库名含特殊字符(如短横线、中文)报错。最稳妥的方式是先构造合法库名列表,再拼接 SQL 执行,而非直接
切换上下文。
实操建议:
从
中筛选:
,排除非法命名库
用
拼接语句,再通过
+
执行,避免游标嵌套开销
每轮执行后检查
,若非 0 则记录错误库名到日志表,不中断整个过程
和
选哪个
两者字段高度重合,但行为差异极大:
是语句级命令,返回实时状态(包括
的近似值),而
是视图,部分字段(如
)在 InnoDB 下始终是估算值,且不反映 MVCC 可见行数。健康检查真正关心的是“是否异常膨胀”“索引是否失效”,不是精确行数。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
实操建议:
优先用
获取单表状态,它比查
快 3–5 倍(尤其在分库多表场景)
若需批量采集,用
动态生成并执行,别试图一条 SQL 查完
警惕
值过大但无实际插入——这说明自增 ID 被大量回滚或删除,可能预示业务逻辑异常
存储过程里怎么存结果又不锁死监控表
直接
容易因长事务拖慢主业务。更糟的是,如果存储过程中途失败,残留的脏数据会让下一次检查误判。
实操建议:
建一张带时间戳和批次号的临时结果表,例如
,用当前时间动态命名,避免并发冲突
所有采集结果先写入该临时表,最后统一
存储过程末尾加
,确保不留垃圾
复杂点在于跨库权限校验和字符集兼容性——比如某库用
,而日志表是
,插入时可能隐式转换失败。这类细节不报错但丢数据,得提前用
校验后再拼 SQL。
information_schemaSELECT COUNT(*) FROM information_schema.TABLESinformation_schemaDATA_LENGTHINDEX_LENGTHANALYZE TABLEperformance_schema.table_io_waits_summary_by_tableANALYZE TABLE `db`.`tbl`TABLESWHERE table_schema NOT IN ('mysql', 'performance_schema', 'sys')USEinformation_schema.SCHEMATAWHERE schema_name REGEXP '^[a-zA-Z0-9_]+$'CONCAT('SELECT "', schema_name, '" AS db_name, ... FROM ', schema_name, '.some_table')PREPAREEXECUTE@@error_countSHOW TABLE STATUSINFORMATION_SCHEMA.TABLESSHOW TABLE STATUSRowsINFORMATION_SCHEMA.TABLESTABLE_ROWSSHOW TABLE STATUS LIKE 'xxx'INFORMATION_SCHEMASELECT CONCAT('SHOW TABLE STATUS FROM `', table_schema, '` LIKE ''', table_name, '''') ...Auto_incrementINSERT INTO health_log SELECT ...health_check_result_20240615_1423INSERT INTO health_log SELECT * FROM temp_table WHERE check_time > NOW() - INTERVAL 5 MINUTEDROP TEMPORARY TABLE IF EXISTS temp_tableutf8mb4_0900_as_csutf8mb4_general_ciSHOW CREATE DATABASE