MySQL是如何处理JSON字段的?存储、查询、修改

635 阅读4分钟

从 MySQL 5.7 开始,引入了对 JSON 数据格式的原生支持,意味着用户可以在 MySQL 数据库中直接存储 JSON 格式的文本,并且能够通过 SQL 查询来操作 JSON 数据。

存储JSON数据

MySQL中对JSON数据的存储是通过一种高效的二进制格式进行的,这种格式专为快速读取和操作优化。这里将详细介绍MySQL存储JSON数据的技术和原理。

存储格式

MySQL将JSON文档存储为一个二进制格式的内部表示,称为Binary JSON(BJSON)。这种格式是一种压缩的二进制格式,它使得数据检索更为高效,尤其是在处理大型或复杂的JSON文档时。

主要特点包括:

  1. 优化的二进制格式

    • JSON文档被转换为一种预解析的二进制格式,这种格式基本上是一种序列化的表示。
    • 该格式包括一个值头部,该头部标记了值的类型和长度,后跟具体的值数据。
  2. 内联键和值

    • 文档的键(即JSON对象的属性名)被存储为长度编码的字符串,这样可以避免在文档中多次出现同一键时的重复存储。
    • 数值和布尔值直接以其原始二进制格式存储,这使得读取时的转换更快。
  3. 长度前缀

    • 每个存储的元素(键或值)都有一个前缀,指示元素的类型和长度,这有助于快速跳过不需要处理的内容。
  4. 文档对象模型(DOM)式的结构

    • 存储格式类似于内存中的文档对象模型,即使是嵌套的JSON对象,也能够被快速地定位和解析。

存储原理

以下是MySQL处理和存储JSON文档的具体步骤:

解析和转换

  • 当JSON数据被插入到MySQL时,它首先被解析为一个内部的树状结构,其中包括嵌套元素的层次关系。

序列化

  • 这个树状结构随后被序列化为一个紧凑的二进制格式。这个过程包括编码所有的键和值,以及构建一个快速查找的索引表,使得可以直接跳转到文档中的特定部分。

存储

  • 序列化后的数据被存储在MySQL的表空间中,具体的存储位置和机制与普通的列类型(如VARCHAR或INT)相似。

读取和操作

  • 当对JSON列进行查询或其他操作时,MySQL可以直接利用二进制格式的优点,快速定位到需要的数据段,无需重新解析整个文档。

在MySQL中,修改JSON数据涉及一系列优化技术,这些技术确保了操作的高效性和灵活性。MySQL提供了多种函数和操作符来修改JSON字段,这些工具可以直接操作存储为二进制格式的JSON数据。下面详细介绍这些技术和原理。

JSON数据的查询方法

MySQL提供了多种方法来查询存储为JSON格式的数据,主要通过以下几种方式:

1. JSON路径表达式

使用JSON路径表达式可以直接定位到JSON文档中的特定部分。这些路径表达式在使用如 JSON_EXTRACT() 或快捷运算符 ->->> 时指定。

  • -> 运算符:获取JSON文档的指定路径的值,并以JSON格式返回。
  • ->> 运算符:获取路径的值,并以普通字符串返回。

例如:

sqlCopy code
SELECT json_col->"$.name" as name
FROM table_name
WHERE json_col->>"$.age" = '30';

2. JSON搜索和修改函数

MySQL还提供了函数来查询和修改JSON数据:

  • JSON_EXTRACT(json_doc, path)json_doc->path: 提取JSON文档中的指定路径的值。
  • JSON_SEARCH(json_doc, 'one', 'search_string') : 查找与指定搜索字符串匹配的文档路径。

3. 利用JSON_TABLE

在MySQL 8.0及以上版本,JSON_TABLE 函数可以将JSON数组或对象转换为关系表的形式,从而可以使用标准的SQL查询这些数据:

sqlCopy code
SELECT jt.*
FROM table_name,
JSON_TABLE(json_col, '$.items[*]' COLUMNS(
    name VARCHAR(40) PATH '$.name',
    price DECIMAL(10,2) PATH '$.price'
)) AS jt;

JSON数据的修改方法

1. JSON修改函数

MySQL使用一系列JSON函数来修改JSON文档,包括:

  • JSON_SET: 用于在JSON文档中添加新的元素或更新现有元素。如果指定的路径不存在,它将创建一个新元素。

  • JSON_INSERT: 只在指定路径不存在时添加新元素,如果路径已存在,则操作不会更改JSON文档。

  • JSON_REPLACE: 只替换路径已存在的元素,如果指定的路径在文档中不存在,则此函数不做任何更改。

  • JSON_REMOVE: 删除JSON文档中的元素。

这些函数都利用了MySQL中JSON的内部二进制表示(BJSON),以快速定位和修改数据,而无需重新解析整个文档。

2. 使用示例

假设有以下JSON列数据:

{
  "name": "John Doe",
  "age": 30,
  "children": [
    {
      "name": "Jane Doe",
      "age": 10
    }
  ]
}

要更新age并添加一个新的email字段,可以使用:

UPDATE table_name
SET json_col = JSON_SET(json_col, '$.age', 31, '$.email', 'john.doe@example.com')
WHERE id = 1;

此命令将age更新为31,并在根级别添加一个email字段。

3. 技术原理

二进制JSON格式(BJSON):

  • 路径缓存: 当进行修改操作时,MySQL使用缓存的路径信息来快速导航至文档中的特定部分,这减少了遍历时间。

  • 局部修改: 修改操作通常是局部的,意味着不需要重写整个文档。例如,增加一个新元素或更新一个现有元素时,只有路径到这个元素的部分区域会被修改。

  • 原地更新: 对于一些简单的更新,如整数或短字符串的更改,MySQL可以在原地进行修改,无需移动其他文档部分,这极大地提高了更新效率。

性能优化

索引支持

虽然不能直接在JSON类型的列上创建索引,但MySQL允许创建虚拟的生成列,并在这些列上建立索引。这些生成列可以抽取JSON文档中的元素。例如:

ALTER TABLE table_name
ADD COLUMN age INT AS (JSON_UNQUOTE(JSON_EXTRACT(json_col, '$.age'))) PERSISTENT;

CREATE INDEX idx_age ON table_name(age);

这种方法利用了MySQL的常规索引功能来优化基于JSON数据的查询,从而间接提高修改操作的性能(因为修改前后可能需要查询数据验证修改)。