MySQL JSON_STORAGE_FREE 怎样判断部分更新留下的空间
来源:17golang原创
时间:2026-10-23 03:51:25 347浏览 收藏
如果你想判断 MySQL 的 JSON 列在更新后是否留下了可以继续利用的空间,关键不是直接看 JSON 文本有多长,而是查询 JSON_STORAGE_FREE(json_col)。这个函数返回的是:JSON 列的二进制表示在合适的部分更新后释放、保留下来的空间。
官方地址:https://dev.mysql.com/doc/refman/8.4/en/json-utility-functions.html
我排查这类问题时,通常先确认三件事:参数确实来自表中的 JSON 列;更新表达式使用了 JSON_SET()、JSON_REPLACE() 或 JSON_REMOVE();本次修改是替换已有值,而不是强行写入更大的新文档。下面按这个顺序拆开。
先区分 JSON 列与普通 JSON 值
JSON_STORAGE_FREE() 接受 JSON 列、合法 JSON 字符串、字面量和用户变量,但它们的语义不同。只有表中的 JSON 列经历了可利用的原地部分更新,才可能得到正数。对字面量或用户变量调用,即使表达式里写了 JSON_SET(),也不会产生表列那种“更新后留下的空闲空间”。
因此,下面的查询适合作为排查入口:
-- 读取列当前文档、初始二进制尺寸和部分更新留下的空间
SELECT
id,
JSON_STORAGE_SIZE(payload) AS storage_size,
JSON_STORAGE_FREE(payload) AS storage_free
FROM event_log
WHERE id = 1001;
JSON_STORAGE_SIZE() 用来观察 JSON 二进制表示的尺寸,JSON_STORAGE_FREE() 用来观察部分更新累计留下的空闲空间。两者回答的是不同问题,不能把其中一个当成另一个的替代品。
用 JSON_SET 做一次可观察的部分更新
要看到正数,最容易复现的方式是把已有字符串替换成更短的值,并且让输入列和目标列保持为同一列:
-- 只替换已有路径,给优化器留下执行部分更新的机会
UPDATE event_log
SET payload = JSON_SET(payload, '$.message', 'ok')
WHERE id = 1001;
-- 读取更新后保留下来的空闲空间
SELECT
JSON_STORAGE_SIZE(payload) AS storage_size,
JSON_STORAGE_FREE(payload) AS storage_free
FROM event_log
WHERE id = 1001;
假设原来的 $.message 值比 ok 长,且其他条件满足,storage_free 可能返回正数。这个数表示释放出来的空间,不代表数据库已经把它返还给操作系统,也不代表整行都没有重写。

用 JSON_STORAGE_SIZE 对照结果
一个容易误解的地方是:部分更新后,JSON_STORAGE_SIZE(payload) 仍然可能反映该列最初写入时的二进制存储尺寸,而 JSON_STORAGE_FREE(payload) 单独记录后续部分更新释放的空间。因此,看到尺寸没有下降,并不等于更新没有生效。
-- 用一次更短的已有值替换,观察尺寸与空闲空间的组合
UPDATE event_log
SET payload = JSON_SET(payload, '$.level', 'i')
WHERE id = 1001;
-- 尺寸用于看基线,空闲空间用于看部分更新的累计结果
SELECT
JSON_STORAGE_SIZE(payload) AS original_binary_size,
JSON_STORAGE_FREE(payload) AS free_after_partial_updates
FROM event_log
WHERE id = 1001;
连续多次合适的部分更新,空闲空间可以累计增加。反过来,如果后一次修改重新占用了这部分空间,返回值也应按当前列的二进制状态理解,而不是当作一条独立更新的日志。
排查为什么结果总是 0
返回 0 很常见,通常先看更新写法而不是怀疑函数:
| 场景 | 典型写法或条件 | 结果判断 |
|---|---|---|
| 直接给列赋 JSON 文本 | SET payload = '{"a":1}' | 完整替换,通常为 0 |
| 使用用户变量 | JSON_STORAGE_FREE(@payload) | 不是表列部分更新,返回 0 |
| 更新表达式输入输出不是同一列 | SET payload_a = JSON_SET(payload_b,...) | 不满足列内原地更新条件 |
| 新增成员或新值更大 | 替换空间不足,或路径原本不存在 | 可能退回完整更新,返回 0 |
| 参数为 NULL | JSON_STORAGE_FREE(NULL) | 返回 NULL |
这里的“可能”很重要:是否采用部分更新由优化器根据列类型、表达式形式、路径和值大小等条件决定,不能只看到 JSON_SET() 就断言一定会得到正数。

形成一套可复用的排查清单
- 先确认列定义确实是
JSON,不要把普通文本列的 JSON 字符串当成同一种情况。 - 确认
UPDATE的输入列和目标列相同,并优先使用JSON_SET、JSON_REPLACE或JSON_REMOVE。 - 确认路径原来存在,替换值没有变得更大;如果是新增成员,先按完整更新来预期。
- 同时读取
JSON_STORAGE_SIZE和JSON_STORAGE_FREE,不要只看 JSON 文本长度。 - 把正数理解为列内部可复用的空闲空间,不把它当作磁盘回收量或整行写入量。
常见问题
JSON_STORAGE_FREE 返回 0 是函数失效吗?
通常不是。直接赋值、使用字面量或用户变量、值变大、增加新成员,以及不满足原地更新条件时,返回 0 都是正常表现。
JSON_STORAGE_FREE 返回的数字就是当前 JSON 大小吗?
不是。它表示部分更新后保留下来的空闲空间;当前二进制尺寸和基线应结合 JSON_STORAGE_SIZE 理解。
只要用 JSON_SET 就一定是部分更新吗?
不一定。还要满足列类型、输入输出列一致、替换已有值且空间条件合适等约束,最终由 MySQL 判断是否能采用部分更新。
小结:判断部分更新留下的空间,先锁定表中的 JSON 列,再看更新函数和替换值,最后用 JSON_STORAGE_SIZE 与 JSON_STORAGE_FREE 组合解释结果。这样即使返回 0,也能快速定位是写法、值大小还是参数类型导致的。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习