默认字符集已从latin1更改为utf8mb4。utf8mb4字符集新增了几个排序规则,包括utf8mb4_ja_0900_as_cs,这是MySQL中首个用于Unicode的日语特定排序规则。
MySQL的JSON功能性方面进行了以下增强或添加:
新增了两个JSON聚合函数:JSON_ARRAYAGG()和JSON_OBJECTAGG()。
JSON_ARRAYAGG()函数将列或表达式作为参数,并将结果聚合为一个单独的JSON数组。表达式可以评估为任何MySQL数据类型;它并不一定是一个JSON值。
JSON_OBJECTAGG()函数接受两个列或表达式,将其解释为键和值,并将结果作为单个JSON对象返回。
新增了JSON实用函数JSON_PRETTY(),它以易于阅读的格式输出现有的JSON值;每个JSON对象成员或数组值都会打印在单独的一行上,并且子对象或数组相对于其父级缩进2个空格。
该函数还可以处理可以解析为JSON值的字符串,将其转换为易于阅读的格式。
在查询中使用ORDER BY对JSON值进行排序时,现在每个值都由可变长度的排序键的一部分表示,而不是固定1K大小的一部分。在许多情况下,这可以减少过度使用内存的情况。例如,标量INT甚至BIGINT值实际上只需要很少的字节,因此剩余的空间(高达90%或更多)被填充占据。此更改对性能有以下好处:
a.排序缓冲区空间的使用更有效,因此与固定长度排序键相比,无需尽早或频繁地将文件排序刷新到磁盘中。这意味着可以在内存中对更多数据进行排序,避免不必要的磁盘访问。
b.较短的键比较起来比较快,提供了明显的性能改进。这对于完全在内存中执行的排序以及需要写入和读取磁盘的排序都适用。
在MySQL 8.0.2中添加了对JSON列值的部分原地更新的支持,这比完全删除现有的JSON值并将其替换为新值的方式更高效。之前更新任何JSON列时都会采取这种方式。要应用此优化,必须使用JSON_SET()、JSON_REPLACE()或JSON_REMOVE()进行更新。不能向正在更新的JSON文档中添加新元素;文档中的值不能比更新之前占用更多的空间。详见关于JSON值的部分更新的详细讨论。
部分更新的JSON文档可以写入二进制日志,占用的空间比记录完整的JSON文档要少。当使用基于语句的复制时,部分更新始终以此方式进行记录。要在基于行的复制中使用此功能,您首先必须设置binlog_row_value_options=PARTIAL_JSON;请参阅此变量的描述以获取更多信息。
在MySQL 8.0.2中添加了JSON实用函数JSON_STORAGE_SIZE()和JSON_STORAGE_FREE()。
JSON_STORAGE_SIZE()函数返回以字节为单位的存储空间,用于在进行任何部分更新(参见前一项)之前JSON文档的二进制表示。此函数还接受JSON文档的有效字符串表示形式作为参数。对于这样的值,JSON_STORAGE_SIZE()函数返回将其转换为JSON文档后其二进制表示使用的空间。如果参数无法解析为有效的JSON文档,则该函数会产生错误,如果参数为NULL,则返回NULL。
JSON_STORAGE_FREE()函数显示类型为JSON的表列在使用JSON_SET()或JSON_REPLACE()进行部分更新后剩余的空间量;如果新值的二进制表示少于先前值的二进制表示,则此值大于零。与JSON_STORAGE_SIZE()类似,JSON_STORAGE_FREE()函数也接受JSON文档的有效字符串表示形式作为参数。对于包含JSON文档字符串表示的变量,JSON_STORAGE_FREE()函数返回零。如果参数无法解析为有效的JSON文档,则该函数会产生错误,如果参数为NULL,则返回NULL。
在MySQL 8.0.2中,添加了对XPath表达式中类似[1to5]的范围的支持。此版本还添加了对last关键字和相对定位的支持,使得?[last]始终选择数组中的最后一个(编号最高的)元素,[last?1]选择倒数第二个元素。last和使用它的表达式还可以包含在范围定义中。例如,?[last-2 to last-1]返回数组中的倒数第二个和倒数第一个元素。
在MySQL 8.0中,添加了一个名为JSON_MERGE_PATCH()的JSON合并函数,旨在符合RFC 7396规范。
当将JSON_MERGE_PATCH()应用于两个JSON对象时,它将把它们合并为一个单独的JSON对象,该对象具有以下集合的成员:
a. 对于第一个对象的每个成员,在第二个对象中没有具有相同键的成员。
b. 对于第二个对象的每个成员,如果在第一个对象中没有具有相同键的成员,并且其值不是JSON的null字面值。
c. 对于两个对象中都存在相同键的每个成员,其中第二个对象中的值不是JSON的null字面值。
作为此工作的一部分,JSON_MERGE()函数已更名为JSON_MERGE_PRESERVE()。在MySQL 8.0中,JSON_MERGE()仍然被识别为JSON_MERGE_PRESERVE()的别名,但现已废弃并可能在未来的MySQL版本中被移除。
在MySQL中,已实现了“最后重复键胜出”的重复键规范化,与RFC 7159和大多数JavaScript解析器保持一致。下面是一个示例,展示了这种行为,只有具有键x的最右边的成员被保留:
mysql> SELECT JSON_OBJECT('x', '32', 'y', '[true, false]',
> 'x', '"abc"', 'x', '100') AS Result;
+------------------------------------+
| Result |
+------------------------------------+
| {"x": "100", "y": "[true, false]"} |
+------------------------------------+
1 row in set (0.00 sec)
在MySQL中,插入到JSON列的值也会按照“最后重复键胜出”的规则进行规范化,如下面的示例所示:
mysql> CREATE TABLE t1 (c1 JSON);
mysql> INSERT INTO t1 VALUES ('{"x": 17, "x": "red", "x": [3, 5, 7]}');
mysql> SELECT c1 FROM t1;
+------------------+
| c1 |
+------------------+
| {"x": [3, 5, 7]} |
+------------------+
这是与先前版本的MySQL不兼容的更改,先前版本中,在这种情况下使用了“首次重复键优先”的算法。
在MySQL 8.0.4中,添加了JSON_TABLE()函数。该函数接受JSON数据并将其作为具有指定列的关系表返回。
JSON_TABLE()函数的语法为:JSON_TABLE(expr, path COLUMNS column_list) [AS alias],其中expr是返回JSON数据的表达式,path是应用于源的JSON路径,column_list是列定义的列表。下面是一个示例:
mysql> SELECT *
-> FROM
-> JSON_TABLE(
-> '[{"a":3,"b":"0"},{"a":"3","b":"1"},{"a":2,"b":1},{"a":0},{"b":[1,2]}]',
-> "$[*]" COLUMNS(
-> rowid FOR ORDINALITY,
->
-> xa INT EXISTS PATH "$.a",
-> xb INT EXISTS PATH "$.b",
->
-> sa VARCHAR(100) PATH "$.a",
-> sb VARCHAR(100) PATH "$.b",
->
-> ja JSON PATH "$.a",
-> jb JSON PATH "$.b"
-> )
-> ) AS jt1;
+-------+------+------+------+------+------+--------+
| rowid | xa | xb | sa | sb | ja | jb |
+-------+------+------+------+------+------+--------+
| 1 | 1 | 1 | 3 | 0 | 3 | "0" |
| 2 | 1 | 1 | 3 | 1 | "3"| "1" |
| 3 | 1 | 1 | 2 | 1 | 2 | 1 |
| 4 | 1 | 0 | 0 |NULL| 0 | NULL |
| 5 | 0 | 1 |NULL|NULL|NULL|[1, 2]|
+-------+------+------+------+------+------+--------+
JSON_TABLE()函数中的表达式部分可以是任何生成有效的JSON文档的表达式,包括JSON字面量、表列或返回JSON的函数调用,比如JSON_EXTRACT(t1, data, '$.post.comments')。