最近做的一个 填报项目,由于填报的字段比较多于是便在数据库当中使用了
longtext
类型的字段直接存储json
数据。
为什么选择直接存储json数据?
但是这里我也是有一点好奇,既然存储为json
,为什么不直接将字段类型设置为json
?由于最近经常会用到数据库存json串,也是下定决心彻底把这块相关的知识给梳理一遍。
从5.7开始,MySQL开始支持json类型,用于存储JSON数据。关于json类型,mysql官网介绍以及使用,本篇文章也是重点整理的官网相关知识:https://dev.mysql.com/doc/refman/8.0/en/json.html#json-values
json数据类型提供了以下优势:
longtext
存储json并不会有这种校验。注意:
JSON 是 JavaScript Object Notation(JavaScript 对象表示法)的缩写,是一个轻量级的,基于文本的,跨语言的数据交换格式。易于阅读和编写。
JSON 的基本数据类型如下:
""
包围的任意数量Unicode字符的集合,特殊符号使用反斜线转义。[]
括起来,元素之间用逗号,
分隔。譬如: [1, "abc", null, true, "10:27:06.000000", {"id": 1}]
值可以是对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个
。值中的字面值中的英文必须使用小写。{}
括起来,键值对之间使用逗号 ,
分隔,键与值之间用冒号 :
分隔。譬如: {"name": "John Doe", "age": 18, "address": {"country" : "china", "zip-code": "10000"}}
一些合法的JSON的实例:
{"a": 1, "b": [1, 2, 3]}
[1, 2, "3", {"a": 4}]
3.14
"plain_text"
JSON 与 JS 对象的关系
很多人搞不清楚 JSON 和 JS 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。如
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON 和 JS 对象互转
要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
简单地说,JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式,例如在 Java中,可以将 JSON 还原为数组或者一个基本对象。
XML本质上也可以作为跨语言的数据交换格式,JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负。
https://blog.csdn.net/weixin_43888891/article/details/130431272
在MySQL 8.0中,优化器可以对JsoN列执行局部就地更新,而不是删除旧文档并将整个新文档写入该列。此优化可以在满足以下条件的更新中执行:
UPDATE mytable SET jcol = '{"a": 10, "b": 25}'
)不能作为部分更新执行。MySQL只能对使用上面列出的三个函数更新值的列执行部分更新。UPDATE mytable SET jcol1 = JSON_SET(jcol2, '$.a', 100)
这样的语句不能作为部分更新执行。JSON_STORAGE FREE()
函数查看JSON列的任何部分更新释放了多少空间。JSON_SET()
执行更新:JSON_STORAGE_FREE(更新后释放的空间)
JSON_STORAGE_FREE(json_val)
返回值:
创建测试表
mysql> CREATE TABLE jtable (jcol JSON);
Query OK, 0 rows affected (0.38 sec)
mysql> INSERT INTO jtable VALUES
-> ('{"a": 10, "b": "wxyz", "c": "[true, false]"}');
Query OK, 1 row affected (0.04 sec)
mysql> SELECT * FROM jtable;
+----------------------------------------------+
| jcol |
+----------------------------------------------+
| {"a": 10, "b": "wxyz", "c": "[true, false]"} |
+----------------------------------------------+
1 row in set (0.00 sec)
现在我们使用JSON_SET()更新列值,这样就可以执行部分更新;在本例中,我们将c键所指向的值(数组[true, false])替换为占用更少空间的值(整数1):
mysql> UPDATE jtable
-> SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wx", "$.c", 1);
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
+-------------------------+
| JSON_STORAGE_FREE(jcol) |
+-------------------------+
| 16 |
+-------------------------+
1 row in set (0.00 sec)
这种部分更新可以使用压缩格式写入二进制日志,以节省空间;这可以通过将 binlog_row_value_options
选项系统变量设置为PARTIAL_JSON
来启用。
binlog_row_value_options
参数是MySQL 8.0.3 版本引入的新参数,该参数主要用于JSON类型的字段更新时,只记录更新的那部分数据到binlog,而不是记录完整的JSON数据,这样能够显著减少JSON字段更新产生的binlog文件大小。
需要注意的是,binlog 中使用 部分更新(Partial Updates),只需满足存储引擎层使用 Partial Updates 的前几个条件,无需考虑变更前后,JSON 文档的空间使用是否会增加。
首先构造测试数据,t 表一共有 16 个文档,每个文档近 10 MB。
create table t(id int auto_increment primary key,
json_col json,
name varchar(100) as (json_col->>'$.name'),
age int as (json_col->'$.age'));
insert into t(json_col) values
(json_object('name', 'Joe', 'age', 24,
'data', repeat('x', 10 * 1000 * 1000))),
(json_object('name', 'Sue', 'age', 32,
'data', repeat('y', 10 * 1000 * 1000))),
(json_object('name', 'Pete', 'age', 40,
'data', repeat('z', 10 * 1000 * 1000))),
(json_object('name', 'Jenny', 'age', 27,
'data', repeat('w', 10 * 1000 * 1000)));
insert into t(json_col) select json_col from t;
insert into t(json_col) select json_col from t;
接下来,测试下述 SQL:update t set json_col = json_set(json_col, '$.age', age + 1);
在以下四种场景下的执行时间:
当然,在生产环境,我们一般很少将 binlog_row_image 设置为 MINIMAL。
但即使如此,只开启存储引擎层和 binlog 中的 Partial Updates,查询时间也比 MySQL 5.7 快 4.87 倍,性能提升还是比较明显的。
https://blog.csdn.net/weixin_43888891/article/details/130419850
https://blog.csdn.net/weixin_43888891/article/details/130438841
JSON_SET()
、JSON_REPLACE()
或JSON_REMOVE()
三个函数可以进行值部分更新。其效率是5.7版本的5倍!虽然5.7版本也有这几个函数,但是并不是部分更新!