前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL 8.0 JSON增强到底有多强?(一)

MySQL 8.0 JSON增强到底有多强?(一)

作者头像
SEian.G
发布2021-07-07 15:00:24
6.9K0
发布2021-07-07 15:00:24
举报
文章被收录于专栏:SEian.G学习记录SEian.G学习记录

我们都知道,从5.7版本开始,MySQL 支持 RFC7159定义的原生JSON数据类型,该类型支持对JSON文档中的数据的有效访问。关于MySQL 8.0 JSON数据类型,后面准备通过一个系列的文章来进行详细的介绍,这样方便大家对MySQL中JSON数据类型的使用有更好的了解;

很多业务人员在用 JSON 数据类型时会遇到各种各样的问题,其中最容易犯的误区就是将类型 JSON 简单理解成字符串类型。但当你看完今天的内容之后,会真正认识到 JSON 数据类型的威力,从而在实际工作中更好地存储非结构化的数据。

与在字符串列中存储JSON格式的字符串相比,JSON数据类型具有以下优势:

* 自动验证存储在JSON列中的JSON文档 。无效的文档会产生错误。 * 优化的存储格式。JSON列中存储的JSON文档将 转换为内部格式,以允许快速读取文档元素。当服务器稍后必须读取以该二进制格式存储的JSON值时,则无需从文本表示形式解析该值。二进制格式的结构使服务器能够直接通过键或数组索引查找子对象或嵌套值,而无需读取文档中它们之前或之后的所有值。

MySQL 8.0还支持RFC 7396中定义的JSON合并补丁格式关系型的结构化存储存在一定的弊端,因为它需要预先定义好所有的列以及列对应的类型。但是业务在发展过程中,或许需要扩展单个列的描述功能,这时,如果能用好 JSON 数据类型,那就能打通关系型和非关系型数据的存储之间的界限,为业务提供更好的架构选择。

一、JSON数据类型

存储在JSON列中的任何JSON文档的大小都限于max_allowed_packet系统变量的值。(当服务器内部在内存中操作JSON值时,该值可以大于此值;当服务器存储一个JSON文档时,这个限制就适用了。)可以使用JSON_STORAGE_SIZE()函数获取存储JSON文档所需的空间量 ;

在MySQL 8.0.13之前,JSON列不能具有非NULL默认值。

JSON列与其他二进制类型的列一样,列也不直接建立索引;相反,可以在生成的列上创建索引,以从该JSON列中提取标量值 。

在MySQL 8.0.17及更高版本中,InnoDB 存储引擎支持JSON数组上的多值索引。后面系列的文章会详细进行介绍

二、创建JSON值

JSON数组包含用逗号分隔并包含在[ ] 字符中的值的列表:

代码语言:javascript
复制
["abc", 10, null, true, false]

JSON对象包含一组键值对,以逗号分隔,并包含在{ }字符内:

代码语言:javascript
复制
{"k1": "value", "k2": 10}

如示例所示,JSON数组和对象可以包含字符串或数字的标量值,JSON空文字或JSON布尔值true或false文字。JSON对象中的键必须是字符串。还允许使用时间(日期,时间或日期时间)标量值:

代码语言:javascript
复制
["12:18:29.000000", "2021-05-10", "2021-05-10 12:18:29.000000"]

JSON数组元素和JSON对象键值中允许嵌套:

代码语言:javascript
复制
[99, {"id": "HK500", "cost": 75.99}, ["hot", "cold"]]
{"k1": "value", "k2": [10, 20]}

还可以从MySQL提供的许多函数中获取JSON值,也可以使用CAST(value as JSON)将其他类型的值强制转换为JSON类型;后面会专门介绍JSON的相关函数

JSON 如果该值是有效的JSON值,则 尝试将值插入到列中会成功,但如果不是,则尝试失败:

代码语言:javascript
复制
mysql>CREATE TABLE t1 (jdoc JSON);
Query OK, 0 rows affected (0.01 sec)
 
mysql>INSERT INTO t1 VALUES('{"key1": "value1", "key2": "value2"}');
Query OK, 1 row affected (0.00 sec)
 
mysq>INSERT INTO t1 VALUES('[1, 2,');
ERROR 3140 (22032): Invalid JSON text: "Invalid value." at position 6 in value for column 't1.jdoc'.

三、JSON合并

MySQL 8.0.3(及更高版本)支持两种合并算法,分别由函数 JSON_MERGE_PRESERVE()和实现 JSON_MERGE_PATCH()。它们在处理重复键的方式上有所不同:JSON_MERGE_PRESERVE()保留重复键的 值,而 JSON_MERGE_PATCH()丢弃除最后一个值以外的所有值。

1、合并数组

在组合多个数组的上下文中,这些数组合并到单个数组中。JSON_MERGE_PRESERVE()通过将稍后命名的数组连接到第一个数组的末尾来实现这一点。JSON_MERGE_PATCH()将每个参数视为一个由单个元素组成的数组(因此索引为0),然后应用“last duplicate key wins”逻辑仅选择最后一个参数。可以比较此查询显示的结果:

代码语言:javascript
复制
8.0支持,5.7不支持
 
mysql>SELECT JSON_MERGE_PRESERVE('[1, 2]', '["a", "b", "c"]', '[true, false]') AS Preserve,JSON_MERGE_PATCH('[1, 2]', '["a", "b", "c"]', '[true, false]') AS Patch\G
*************************** 1. row ***************************
Preserve: [1, 2, "a", "b", "c", true, false]
   Patch: [true, false]
1 row in set (0.00 sec)

2、合并对象

合并时,多个对象将产生一个对象。JSON_MERGE_PRESERVE()通过组合数组中该键的所有唯一值来处理具有相同键的多个对象;然后将此数组用作结果中该键的值。JSON_MERGE_PATCH() 丢弃从左到右查找重复键的值,以便结果仅包含该键的最后一个值。以下查询说明重复键的结果不同a:

代码语言:javascript
复制
mysql>SELECT JSON_MERGE_PRESERVE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}', '{"c": 5, "d": 3}') AS Preserve,JSON_MERGE_PATCH('{"a": 3, "b": 2}', '{"c": 3, "a": 4}', '{"c": 5, "d": 3}') AS Patch\G
*************************** 1. row ***************************
Preserve: {"a": [1, 4], "b": 2, "c": [3, 5], "d": 3}
   Patch: {"a": 4, "b": 2, "c": 5, "d": 3}
1 row in set (0.01 sec)

在需要数组值的上下文中使用的非数组值是自动包装的:该值被[和]字符包围,以将其转换为数组。在下面的语句中,每个参数都自动包装为一个数组([1],[2])。然后合并这些结果以生成单个结果数组。与前两种情况一样,JSON_MERGE_PRESERVE()组合具有相同键的值;JSON_MERGE_PATCH()丢弃除最后一个键以外的所有重复键的值,如下所示:

代码语言:javascript
复制
mysql>SELECT JSON_MERGE_PRESERVE('1', '2') AS Preserve,JSON_MERGE_PATCH('1', '2') AS Patch\G
*************************** 1. row ***************************
Preserve: [1, 2]   Patch: 2
1 row in set (0.00 sec)

数组和对象值是通过将对象自动包装为数组并通过组合值或根据合并函数的选择(JSON_MERGE_PRESERVE()JSON_MERGE_PATCH())选择“last duplicate key wins”来合并数组,从而合并数组和对象值 ,如以下示例所示:

代码语言:javascript
复制
mysql>SELECT JSON_MERGE_PRESERVE('[10, 20]', '{"a": "x", "b": "y"}') AS Preserve,JSON_MERGE_PATCH('[10, 20]', '{"a": "x", "b": "y"}') AS Patch\G
*************************** 1. row ***************************
Preserve: [10, 20, {"a": "x", "b": "y"}]
   Patch: {"a": "x", "b": "y"}
1 row in set (0.00 sec)

四、JSON值的部分更新

在MySQL 8.0中,优化器可以执行JSON列的局部就地更新,而不是删除旧文档并将新文档全部写入该列。可以对满足以下条件的更新执行此优化:

* 正在更新的列被声明为 JSON。

* 该UPDATE语句使用任何的三个功能 JSON_SET(), JSON_REPLACE()或 JSON_REMOVE()更新列。列值的直接赋值(例如,UPDATE mytable SET jcol='{“A”:10,“b”:25}’)不能作为部分更新执行。

在一个UPDATE语句中更新多个JSON列可以用这种方式进行优化;MySQL只能对那些使用刚刚列出的三个函数更新其值的列执行部分更新。

* 输入列和目标列必须是同一列;诸如UPDATE mytable SET jcol1 = JSON_SET(jcol2, ‘$.a’, 100)不能作为部分更新执行的语句。

只要输入列和目标列相同,更新可以以任何组合使用对上一项中列出的任何函数的嵌套调用。

* 所有更改都会用新值替换现有的数组或对象值,并且不会将任何新元素添加到父对象或数组。

* 被替换的值必须至少与替换值一样大。换句话说,新值不能大于旧值。

当以前的部分更新为较大的值留下了足够的空间时,可能会出现此要求的例外情况。可以使用函数JSON_STORAGE_FREE()查看JSON列的任何部分更新释放了多少空间。

可以使用节省空间的紧凑格式将此类部分更新写入二进制日志。可以通过将binlog_row_value_options 系统变量设置为启用此功能PARTIAL_JSON。该参数8.0才开始支持;

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA的辛酸事儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、JSON数据类型
  • 二、创建JSON值
  • 三、JSON合并
  • 四、JSON值的部分更新
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档