视图中禁止裸用JSON_EXTRACT,必须执行UNQUOTE+CAST+VALID三步操作,并通过生成列与索引提升性能。

视图里直接写 JSON_EXTRACT 或 JSON_VALUE 是最常见也最容易翻车的做法——它不报错,但会悄悄让查询变慢、结果不准、维护成本飙升。
为什么不能在视图里裸用 JSON_EXTRACT
裸用指不加类型转换、不处理 NULL、不校验合法性,直接把 JSON_EXTRACT(payload, '$.user.id') 当列名扔进视图定义里。后果很实在:
- 同一路径在多个字段重复出现(比如
$.user.id和$.user.email),JSON 结构微调时得改视图、改业务 SQL、改索引,漏一处就出 NULL -
JSON_EXTRACT返回带双引号的字符串(如"123"),后续做JOIN或WHERE id = 123会隐式转成数字再比对,慢且不可靠 - MySQL 不会缓存单行 JSON 的解析结果,一个视图里写 4 个
JSON_EXTRACT,等于对同一字段解析 4 次 - PostgreSQL 用
->>看似简洁,但它对不存在的 key 返回NULL,而->返回json类型,混用会导致类型不匹配错误
视图中必须做的三件事:UNQUOTE + CAST + VALID
真正能长期跑下去的视图,必须把“提取 → 去引号 → 转类型 → 校验”这四步固化进去。不是可选项,是底线:
- 对字符串字段,一律套
JSON_UNQUOTE(JSON_EXTRACT(...)),别信->>在所有场景都安全(比如 MySQL 5.7 不支持嵌套数组访问) - 对数字字段,必须显式
CAST(... AS UNSIGNED)或CAST(... AS DECIMAL(10,2)),避免后续聚合或比较出错 - 在视图
WHERE子句或生成列定义前,加JSON_VALID(payload) = 1(MySQL)或payload::jsonb IS NOT NULL(PostgreSQL),过滤掉非法 JSON 行——否则 NULL 会污染整个结果集 - SQL Server 视图里必须先用
ISJSON(payload) = 1过滤,再调JSON_VALUE,否则静默返回 NULL,你根本不知道哪条数据丢了
生成列 + 索引才是性能关键,不是视图本身
视图只是封装逻辑,不解决性能问题。真正提速靠的是把常用 JSON 字段物理化为生成列并建索引:
- MySQL 中用
STORED生成列(VIRTUAL不能建索引),例如:user_id INT AS (CAST(JSON_UNQUOTE(JSON_EXTRACT(data, '$.user.id')) AS UNSIGNED)) STORED - PostgreSQL 中优先用
jsonb类型 + GIN 索引,或表达式索引:CREATE INDEX idx_user_status ON events ((data->>'status')) - 别试图给原始 JSON 列建索引——MySQL 不支持,PostgreSQL 的 GIN 索引只加速
@>、?这类操作,不加速->>提取 - 如果字段高频用于
JOIN或GROUP BY,宁可冗余存一遍关系列,也别依赖运行时解析
复杂点不在语法,而在边界判断:JSON 路径是否大小写敏感、空字符串算不算合法 JSON、NULL 值要不要参与聚合、数组元素匹配用 @> 还是 ?——这些细节不提前踩一遍,上线后查半天才发现是数据库版本或字符集惹的祸。


















