管理 JSON 列和索引
当表中的每一行具有相同列时,关系数据库效果最佳。 定义一次结构,每个记录都遵循该结构。 此设计适用于字段可预测的情况下,如客户、订单或发票等数据。 但某些数据因记录而异。 需要存储的属性取决于项的类型、数据源或用户所做的选择。 传统的表格设计迫使你要么创建许多对大多数行都为空的列,要么将数据分散到多个表。 JSON 列提供另一个选项:将变量部分存储为 JSON,同时将可预测部分保存在常规列中。
例如,电子商务产品目录具有适用于每个项目的公用字段,例如产品名称、价格和类别。 但衬衫需要大小和颜色,笔记本电脑需要处理器速度和屏幕大小,书籍需要作者和其他属性。 使用 JSON,可将公共字段存储为列,并将特定于类别的属性放入 JSON 列中。 无需更改表结构即可添加新的产品类型。
了解何时使用 JSON 列
JSON 列 允许使用熟悉的 SQL 语法查询和索引半结构化数据。 无需单独的 NoSQL 数据库来处理灵活的数据。 对于以下方案,请考虑 JSON:
- 用户首选项 - 添加功能时,主题、语言和通知选项等设置因用户而异。
- API 响应 - 来自外部服务的数据具有可在提供程序更新其 API 时更改的嵌套结构。
- 审核日志 - 状态前后捕获的记录需要随着表架构的发展而进行调整。
- 多租户应用程序 - 不同的客户需要不同的自定义字段。
- 灵活的元数据 - 标记、标签和属性,这些标记和属性因记录而异,并且不适合固定架构。
创建和查询 JSON 列
SQL Server 2025 引入了本机 json 数据类型,该数据类型以优化的二进制格式存储 JSON 文档,从而方便地进行查询与操作。 本机类型在读取时更高效(因为文档已被解析),在写入时也更高效(更新能够在不重写整个文档的情况下修改单个值),并且与将 JSON 作为NVARCHAR(MAX)存储相比,具有更好的存储压缩效果。
对于早期版本的 SQL Server,将 JSON 存储在 NVARCHAR(MAX) 列中。
若要从 JSON 读取值,请使用 JSON 函数 ,例如 JSON_VALUE 提取单个值或 JSON_QUERY 返回对象或数组。 如果经常查询 JSON 属性,可以在提取该属性的计算列上创建索引。
以下示例创建包含 JSON 列的表、插入文档、查询特定属性、更新值,并在经常访问的字段上创建索引:
-- Create table with native JSON type (SQL Server 2025+)
CREATE TABLE ConfigurationData (
ConfigID INT PRIMARY KEY,
ConfigSettings JSON NOT NULL
);
-- Insert JSON documents
INSERT INTO ConfigurationData (ConfigID, ConfigSettings)
VALUES (1, '{"theme":"dark","language":"en","notifications":true}');
INSERT INTO ConfigurationData (ConfigID, ConfigSettings)
VALUES (2, '{"theme":"light","language":"fr","notifications":false}');
-- Query JSON properties
SELECT ConfigID,
JSON_VALUE(ConfigSettings, '$.theme') AS Theme,
JSON_VALUE(ConfigSettings, '$.language') AS Language,
JSON_QUERY(ConfigSettings, '$') AS FullConfig
FROM ConfigurationData;
-- Update a single property using the modify method (SQL Server 2025+ preview)
UPDATE ConfigurationData
SET ConfigSettings.modify('$.theme', 'light')
WHERE ConfigID = 1;
-- Alternative: JSON_MODIFY works with both JSON and NVARCHAR(MAX) columns
UPDATE ConfigurationData
SET ConfigSettings = JSON_MODIFY(CAST(ConfigSettings AS NVARCHAR(MAX)), '$.notifications', CAST(0 AS BIT))
WHERE ConfigID = 1;
-- Create index on frequently queried JSON property
ALTER TABLE ConfigurationData
ADD ThemeValue AS JSON_VALUE(ConfigSettings, '$.theme');
CREATE INDEX IX_Theme ON ConfigurationData(ThemeValue);
此示例创建一个包含 JSON 存储用户配置设置的列的表。 这些 INSERT 语句将 JSON 文档添加为字符串文本。 若要读取特定值,JSON_VALUE 提取主题和语言等标量值,同时 JSON_QUERY 返回整个 JSON 对象。 该方法 .modify() (当前以预览版提供)更新单个属性,而无需重写整个文档。
json由于该类型不能用作索引键列,因此该示例将创建一个计算列来提取主题值,然后为该计算列编制索引。
合并关系和 JSON 结构
JSON 列最适合每条记录数据结构各异的情况。 如果每行具有相同的数据类型的字段,则常规列更适合。 可以获取原生数据类型验证、无需 JSON 路径语法的更简单查询,并直接对列进行索引。 对需要灵活性的数据部分使用 JSON,并将可预测部分保留在类型化列中。
对于需要变量元数据的产品,可以将关系结构与 JSON 灵活性相结合。 下面是一个示例:
-- Product with flexible metadata (SQL Server 2025+)
CREATE TABLE ProductMetadata (
ProductID INT PRIMARY KEY,
AdditionalAttributes JSON NOT NULL
CHECK (JSON_PATH_EXISTS(AdditionalAttributes, '$.weight') = 1),
FOREIGN KEY (ProductID) REFERENCES Product(ProductID)
);
-- Store flexible product attributes
INSERT INTO ProductMetadata (ProductID, AdditionalAttributes)
VALUES (1, '{"dimensions":{"length":10,"width":5,"height":8},"weight":2.5,"color":"blue"}');
-- Query nested JSON properties
SELECT ProductID,
JSON_VALUE(AdditionalAttributes, '$.weight') AS Weight,
JSON_VALUE(AdditionalAttributes, '$.dimensions.length') AS Length
FROM ProductMetadata;
考虑 JSON 设计原则
实现 JSON 列时应用以下原则:
- 将 JSON 用于半结构化数据 - 存储灵活的数据结构,这些结构因记录而异,而不是具有一致的架构的数据。
- 索引经常查询的路径 - 创建计算列,其中包含经常查询的 JSON 属性上的索引。
-
验证所需的属性 - 使用
CHECK约束JSON_PATH_EXISTS来确保必填字段存在。 - 平衡灵活性与结构 - 在常规列中保留可预测的数据,并仅对变量部分使用 JSON。
JSON 列在保持 SQL 查询功能的同时,为可变数据提供了架构灵活性,但应作为结构化数据关系设计的补充而非替代。