JSON_VALUE在WHERE中慢是因为每次执行都全表解析JSON字符串且不走索引,必须通过持久化计算列加索引才能加速;OPENJSON比多个JSON_VALUE快因只解析一次;路径须以$开头、中文键需转义;lax为默认模式,strict仅用于强校验。

为什么JSON_VALUE在WHERE里一用就慢?
因为每次执行都要全表解析 JSON 字符串,JSON_VALUE(data, '$.status') 不会走索引,哪怕你加了计算列也没用——除非显式建索引。SQL Server 不会自动为 JSON 路径创建索引,它只认普通列或计算列。常见错误是直接写 WHERE JSON_VALUE(@json, '$.id') = 123 做参数匹配,这在存储过程中调用时等于放弃所有索引能力。
- 必须先把路径提取结果固化为「持久化计算列」:
ALTER TABLE Orders ADD status AS JSON_VALUE(data, '$.status') PERSISTED - 再在这个列上建索引:
CREATE INDEX IX_Orders_status ON Orders(status) - 查询时改用该列:
WHERE status = 'done',而不是再调用JSON_VALUE - 注意:计算列类型要和预期值一致,比如状态是字符串就得声明为
NVARCHAR(20),别用NVARCHAR(4000)默认长度,否则索引效率下降
OPENJSON + WITH 为什么比一堆JSON_VALUE快?
当你要从同一段 JSON 提取 3 个以上字段,或者字段跨层级(如 $.user.name 和 $.order.items[0].price),硬写多个 JSON_VALUE 不仅难读,还会让 SQL Server 对同一 JSON 字符串重复解析多次。而 OPENJSON 只解析一次,再通过 WITH 子句批量映射成关系型结构。
-
OPENJSON必须配WITH才能生成可用列;不带WITH返回的是三列字符串(key、value、type),没法直接JOIN或WHERE - 路径必须以
$开头:'$.user.name'合法,'user.name'静默失败,返回空结果 - 中文键名必须转义:
'$.["收货地址"]',不能写'$.收货地址' - 嵌套数组要用
CROSS APPLY分层展开,例如先OPENJSON(@json, '$.orders'),再对每行CROSS APPLY OPENJSON(value, '$.items')
lax vs strict 模式怎么选?
默认 lax 模式会静默返回 NULL,适合容忍缺失字段的场景;strict 模式会在路径不存在时直接报错,适合强校验逻辑。但别在性能敏感路径上用 strict——错误抛出本身有开销,且无法被索引优化覆盖。
- 查询场景一律用
lax(不用显式写,就是默认);只有在存储过程入口做数据校验时才考虑strict -
ISJSON(@json) != 1就该直接RETURN,别让后续 JSON 函数白跑 -
JSON_VALUE返回NULL不代表字段为空,可能是路径错、类型错、或根本不是标量——先确认ISJSON和路径合法性,再查业务含义
大 JSON(>2MB)查询卡顿怎么办?
SQL Server 的 JSON 函数底层全是字符串操作,没有真正的 JSON 类型。一旦 JSON 超过 2MB,OPENJSON 解析耗时呈非线性增长,反复调用 JSON_MODIFY 更是雪上加霜。
- 别在存储过程中反复修改大 JSON;拆到应用层做 patch,只把最终结果存回数据库
- 高频查询字段优先扁平化:把
$.user.email单独抽成user_email NVARCHAR(256)列,加索引 - 避免在
FOR JSON输出前做复杂聚合;先SELECT ... INTO #tmp,再SELECT * FROM #tmp FOR JSON PATH - 如果必须处理大 JSON,确保
@json_param声明为NVARCHAR(MAX),而非NVARCHAR(4000)或VARCHAR——后者会导致截断或乱码,尤其是含 Base64 图片时
实际最常被忽略的一点:JSON 路径里的大小写、空格、引号,全都是硬匹配。写错一个字符,函数就静默返回 NULL,而这个 NULL 很容易被当成“业务上没填”,引发下游逻辑误判。调试时第一反应不该是查数据,而是用 SELECT ISJSON(@json), JSON_VALUE(@json, '$.xxx') 单独验证路径是否真能取到值。



















