应将高频过滤字段持久化为计算列并建索引,而非在WHERE中直接用JSON_VALUE;批量导入优先用TVP而非OPENJSON解析JSON字符串;JSON_MODIFY更新前需校验路径存在;SQL Server 2022不支持json数据类型。

用 JSON_VALUE 和 JSON_QUERY 提取字段时,别直接嵌套在 WHERE 中
SQL Server 2022 的 JSON_VALUE 在 WHERE 子句里直接使用(如 WHERE JSON_VALUE(data, '$.price') > 100)会导致全表扫描——因为函数无法利用索引,且每次都要解析整个 JSON 字符串。
真正高效的做法是:提前把关键字段持久化为计算列并建索引。例如:
ALTER TABLE products ADD price_as_num AS CAST(JSON_VALUE(data, '$.price') AS DECIMAL(10,2)) PERSISTED; <p>CREATE INDEX IX_products_price_as_num ON products(price_as_num);
这样后续查询就能走索引,而不是每次调用 JSON_VALUE 去解析文本。
- 只对高频过滤/排序的 JSON 字段做持久化,避免冗余列膨胀
-
PERSISTED是必须的,否则索引无法建立在计算列上 - 注意
JSON_VALUE返回的是字符串,务必显式CAST成目标类型,否则比较行为可能出人意料
批量导入 JSON 数组?优先用 OPENJSON + 表值参数,别拼字符串
常见错误是把前端传来的 JSON 数组(如 [{"id":1,"name":"A"},{"id":2,"name":"B"}])当字符串塞进存储过程,再用 OPENJSON(@json) 解析——这在高并发下会显著拖慢性能,因为每次调用都触发 JSON 解析和内存分配。
更优路径是让应用层把 JSON 数组反序列化后,用表值参数(TVP)传入。SQL Server 2022 完全支持 TVP 与 OPENJSON 协同:
-- 假设已定义类型: CREATE TYPE ProductList AS TABLE (id INT, name NVARCHAR(50)); CREATE PROCEDURE sp_upsert_products @products ProductList READONLY AS BEGIN MERGE products AS t USING @products AS s ON t.id = s.id WHEN MATCHED THEN UPDATE SET name = s.name WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name); END;
这样绕开了 JSON 解析开销,也规避了 SQL 注入风险。
- TVP 需提前在数据库中定义类型,不能临时创建
- Node.js / .NET 客户端需用对应驱动支持 TVP(tedious、SqlClient 均支持)
- 如果必须用 JSON 入参,至少加
WITH子句明确 schema,避免OPENJSON自动推断类型带来的隐式转换开销
JSON_MODIFY 更新深层嵌套字段时,路径写错会静默失败
JSON_MODIFY 对不存在的路径默认不报错,而是原样返回输入 JSON——比如想更新 $.specs.wheelSize,但 specs 对象根本不存在,结果就是什么都没改,还看不出异常。
安全做法是分两步:先用 ISJSON + JSON_VALUE 确认路径存在,再执行修改;或用 JSON_MODIFY 的 append 模式配合条件判断:
DECLARE @data NVARCHAR(MAX) = '{"name":"bike"}';
SET @data = JSON_MODIFY(
@data,
'append $.tags',
'new'
);
-- 这会追加到 tags 数组末尾;如果 tags 不存在,会自动创建数组- 用
append $.路径前缀可避免“父对象不存在”导致的静默失效 - 更新数组元素要用数组索引(如
$[0].name),别用点号路径 -
JSON_MODIFY不支持通配符或动态索引,想批量更新数组项得靠OPENJSON+FOR JSON重构
SQL Server 2022 的 JSON 数据类型不是万能加速器
2025 引入的 json 数据类型(二进制存储)确实在读取性能上有提升,但它在 2022 版本中并不可用——强行在 2022 上声明 json 列会报错 Incorrect syntax near 'json'。
当前能用的只有 NVARCHAR(MAX) 存 JSON 文本,所有函数(JSON_VALUE、JSON_QUERY 等)也都基于此。所谓“JSON 类型支持”,是 2025+ 才落地的特性。
- 别被文档标题误导,检查
SELECT @@VERSION确认真实版本 - 2022 中唯一能加速 JSON 查询的方式,还是前面说的持久化计算列 + 索引
- 如果升级无望,又需要高频 JSON 查询,考虑把部分结构扁平化到关系列,而非强依赖 JSON 函数
真正卡住性能的往往不是 JSON 功能本身,而是没意识到 JSON_VALUE 在 WHERE 里等于放弃索引,或者把 JSON 当成银弹去存一切字段——该拆的关系字段,迟早得拆。


















