直接查 information_schema.tables 可得数据库逻辑大小,但剩余空间需用系统命令查磁盘,二者必须分开;data_free 不是磁盘剩余,仅表示表空间内未分配页的空闲量。

直接查 information_schema.TABLES 就能拿到当前库的逻辑大小,但「剩余空间」不是数据库层面的概念——MySQL 不暴露磁盘剩余量,得靠系统命令配合;二者必须分开查,不能混为一谈。
查当前数据库总大小(逻辑占用)
执行前确保已用 USE your_db_name 切换到目标库,或在查询中显式指定 TABLE_SCHEMA:
SELECT CONCAT(ROUND(SUM(DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2), ' MB') AS 'total_size', CONCAT(ROUND(SUM(DATA_LENGTH) / 1024 / 1024, 2), ' MB') AS 'data_size', CONCAT(ROUND(SUM(INDEX_LENGTH) / 1024 / 1024, 2), ' MB') AS 'index_size' FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE();
-
DATABASE()返回当前选中的库名,比硬编码更安全,也避免误查其他库 - 结果是 InnoDB 的估算值,不包含 redo log、binlog、临时文件、undo log 等,仅反映表数据+索引的逻辑大小
- 如果没执行
USE就直接运行,DATABASE()返回NULL,查询结果为空——这是常见静默失败点
查磁盘剩余空间(物理层面)
MySQL 自身无法返回磁盘剩余量,必须退出 MySQL 客户端,用系统命令查数据目录所在挂载点:
- Linux 上先确认数据目录:
SELECT @@datadir;,通常为/var/lib/mysql - 再执行:
df -h /var/lib/mysql(替换为你实际的 datadir 路径) - 关键看
Avail列,不是Used——后者容易被误读为“还能用多少”,其实是已用空间
注意:df 显示的是整个文件系统剩余,不是 MySQL 专属剩余;如果 datadir 跨多个挂载点(如表空间文件放在不同路径),需分别检查。
为什么不能用 data_free 当“剩余空间”?
DATA_FREE 字段常被误解为“可用空间”,但它只对 InnoDB 表有意义,且含义是:该表所在表空间内尚未分配给任何页的空闲空间,不是磁盘剩余,也不代表你能插入多少新数据。
- 对
innodb_file_per_table = ON的表,DATA_FREE多为 0 或极小值,因为每个表独占一个 .ibd 文件,空间用完即扩容文件 - 对共享表空间(
innodb_file_per_table = OFF),DATA_FREE是 ibdata1 内的碎片空闲量,无法直接用于预估写入能力 - 它不随 DELETE 自动释放,也不等同于
OPTIMIZE TABLE后释放的空间——后者只是归还给表空间,未必返还给操作系统
快速组合命令(适合运维脚本)
把逻辑大小和磁盘剩余打包成一行输出,方便监控或巡检:
mysql -Nse "SELECT CONCAT(ROUND(SUM(DATA_LENGTH+INDEX_LENGTH)/1024/1024,2),' MB') FROM information_schema.TABLES WHERE TABLE_SCHEMA='your_db_name';" && df -h $(mysql -Nse "SELECT @@datadir;") | awk 'NR==2 {print \"disk_avail: \" $4}'
- 第一段查库逻辑大小,
-Nse去掉列名和多余空格 - 第二段用
$(mysql -Nse "SELECT @@datadir;")动态获取路径,避免硬编码 -
awk 'NR==2'提取df输出第二行(即实际挂载行),$4是 Avail 列 - 别漏掉引号和分号,shell 解析敏感;生产环境建议封装为函数,加错误判断
真正要预警的是磁盘 Avail 接近 0,而不是 DATA_FREE 变小——后者只提示你该考虑 OPTIMIZE TABLE 或归档了。











