从 MySQL 5.7 开始,引入了对 JSON 数据格式的原生支持,意味着用户可以在 MySQL 数据库中直接存储 JSON 格式的文本,并且能够通过 SQL 查询来操作 JSON 数据。
存储JSON数据
MySQL中对JSON数据的存储是通过一种高效的二进制格式进行的,这种格式专为快速读取和操作优化。这里将详细介绍MySQL存储JSON数据的技术和原理。
存储格式
MySQL将JSON文档存储为一个二进制格式的内部表示,称为Binary JSON(BJSON)。这种格式是一种压缩的二进制格式,它使得数据检索更为高效,尤其是在处理大型或复杂的JSON文档时。
主要特点包括:
-
优化的二进制格式:
- JSON文档被转换为一种预解析的二进制格式,这种格式基本上是一种序列化的表示。
- 该格式包括一个值头部,该头部标记了值的类型和长度,后跟具体的值数据。
-
内联键和值:
- 文档的键(即JSON对象的属性名)被存储为长度编码的字符串,这样可以避免在文档中多次出现同一键时的重复存储。
- 数值和布尔值直接以其原始二进制格式存储,这使得读取时的转换更快。
-
长度前缀:
- 每个存储的元素(键或值)都有一个前缀,指示元素的类型和长度,这有助于快速跳过不需要处理的内容。
-
文档对象模型(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数据的查询,从而间接提高修改操作的性能(因为修改前后可能需要查询数据验证修改)。