MySQL学习笔记(Day009:JSON)
@(MySQL学习)
[TOC]
一. MySQL JSON类型
1. JSON介绍
- JSON(
J
avaS
criptO
bjectN
otation)是一种轻量级的数据交换语言,并且是独立于语言的文本格式。 - 一些
NoSQL数据库
选择JSON
作为其数据存储格式,比如:MongoDB、CouchDB等。 - MySQL
5.7.x
开始支持JSON数据类型。
2. JSON格式示例
1 | -- |
3. JSON VS BLOB
JSON
- JSON数据可以做有效性检查;
- JSON使得查询性能提升;
- JSON支持部分属性索引,通过虚拟列的功能可以对JSON中的部分数据进行索引;
BLOB
- BLOB类型无法在数据库层做约束性检查;
- BLOB进行查询,需要遍历所有字符串;
- BLOB做只能做指定长度的索引;
5.7之前,只能把JSON当作BLOB进行存储。数据库层面无法对JSON数据做一些操作,只能由应用程序处理。
4.结构化和非结构化
结构化
- 二维表结构(行和列)
- 使用SQL语句进行操作
非结构化
- 使用Key-Value格式定义数据,无结构定义
- Value可以嵌套Key-Value格式的数据
- 使用JSON进行实现
1 | -- |
1 | # |
5. JSON操作示例
5.1 JSON入门
1 | -- |
5.2 JSON常用函数介绍
1 | -- |
5.3 JSON创建索引
JSON
类型数据本身无法直接
创建索引,需要将需要索引的JSON数据
重新生成虚拟列(Virtual Columns)
之后,对该列
进行索引
新建表时创建JSON索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131mysql> create table test_inex_1(
-> data json,
-> gen_col varchar(10) generated always as (json_extract(data, '$.name')), -- 抽取data中的name, 生成新的一列,名字为gen_col
-> index idx (gen_col) -- 将gen_col 作为索引
-> );
Query OK, 0 rows affected (0.13 sec)
mysql> show create table test_index_1;
-- -----省略表格线-----
| test_index_1 | CREATE TABLE `test_index_1` (
`data` json DEFAULT NULL,
`gen_col` varchar(10) GENERATED ALWAYS AS (json_extract(data, '$.name')) VIRTUAL,
KEY `idx` (`gen_col`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
-- -----省略表格线-----
1 row in set (0.00 sec)
mysql> insert into test_index_1(data) values ('{"name":"tom", "age":18, "address":"SH"}');
Query OK, 1 row affected (0.04 sec)
mysql> insert into test_index_1(data) values ('{"name":"jim", "age":28, "address":"SZ"}');
Query OK, 1 row affected (0.03 sec)
mysql> select * from test_index_1;
+---------------------------------------------+---------+
| data | gen_col |
+---------------------------------------------+---------+
| {"age": 18, "name": "tom", "address": "SH"} | "tom" |
| {"age": 28, "name": "jim", "address": "SZ"} | "jim" |
+---------------------------------------------+---------+
2 rows in set (0.00 sec)
mysql> select json_extract(data,"$.name") as username from test_index_1 where gen_col="tom"; -- 如果这样做,为空,原因如下
Empty set (0.00 sec)
mysql> select hex('"');
+----------+
| hex('"') |
+----------+
| 22 | -- 双引号的 16进制
+----------+
1 row in set (0.00 sec)
mysql> select hex(gen_col) from test_index_1;
+--------------+
| hex(gen_col) |
+--------------+
| 226A696D22 | -- 双引号本身也作为了存储内容
| 22746F6D22 |
+--------------+
2 rows in set (0.00 sec)
mysql> select json_extract(data,"$.name") as username from test_index_1 where gen_col='"tom"'; -- 使用'"tome"',用单引号括起来
+----------+
| username |
+----------+
| "tom" | -- 找到了对应的数据
+----------+
1 row in set (0.00 sec)
mysql> explain select json_extract(data,"$.name") as username from test_index_1 where gen_col='"tom"'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test_index_1
partitions: NULL
type: ref
possible_keys: idx -- 使用了 key idx
key: idx
key_len: 43
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
---
--- 建立表的时候去掉双引用
---
mysql> create table test_index_2 (
-> data json,
-> gen_col varchar(10) generated always as (
-> json_unquote( -- 使用json_unquote函数进行去掉双引号
-> json_extract(data, "$.name")
-> )),
-> key idx(gen_col)
-> );
Query OK, 0 rows affected (0.13 sec)
mysql> show create table test_index_2;
-- -----省略表格线-----
| test_index_2 | CREATE TABLE `test_index_2` (
`data` json DEFAULT NULL,
`gen_col` varchar(10) GENERATED ALWAYS AS (json_unquote(
json_extract(data, "$.name")
)) VIRTUAL,
KEY `idx` (`gen_col`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
-- -----省略表格线-----
1 row in set (0.00 sec)
mysql> insert into test_index_2(data) values ('{"name":"tom", "age":18, "address":"SH"}');
Query OK, 1 row affected (0.03 sec)
mysql> insert into test_index_2(data) values ('{"name":"jim", "age":28, "address":"SZ"}');
Query OK, 1 row affected (0.02 sec)
mysql> select json_extract(data,"$.name") as username from test_index_2 where gen_col="tom"; -- 未加单引号
+----------+
| username |
+----------+
| "tom" | -- 可以找到数据
+----------+
1 row in set (0.00 sec)
mysql> explain select json_extract(data,"$.name") as username from test_index_2 where gen_col="tom"\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test_index_2
partitions: NULL
type: ref
possible_keys: idx -- 使用了 key idx
key: idx
key_len: 43
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)修改已存在的表创建JSON索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79--
-- 使用之前的user表操作
--
mysql> show create table user;
-- -----省略表格线-----
| user | CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`data` json DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 |
-- -----省略表格线-----
1 row in set (0.00 sec)
mysql> select * from user;
+-----+------------------------------------------------------+
| uid | data |
+-----+------------------------------------------------------+
| 1 | {"age": 18, "name": "tom", "address": ["SZ", "BJ"]} |
| 2 | {"age": 28, "mail": "jim@163.com", "name": "jim"} |
| 4 | {"age": 33, "name": "jery", "email": "jery@163.com"} |
+-----+------------------------------------------------------+
mysql> alter table user
-> add user_name varchar(32)
-> generated always as (json_extract(data,"$.name")) virtual;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- virtual 关键字是不将该列的字段值存储,对应的是stored
mysql> select user_name from user;
+-----------+
| user_name |
+-----------+
| "tom" |
| "jim" |
| "jery" |
+-----------+
3 rows in set (0.00 sec)
mysql> alter table user add index idx(user_name);
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select * from user where user_name='"tom"'; -- 加单引号
+-----+-----------------------------------------------------+-----------+
| uid | data | user_name |
+-----+-----------------------------------------------------+-----------+
| 1 | {"age": 18, "name": "tom", "address": ["SZ", "BJ"]} | "tom" |
+-----+-----------------------------------------------------+-----------+
1 row in set (0.00 sec)
mysql> explain select * from user where user_name='"tom"'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
partitions: NULL
type: ref
possible_keys: idx -- 使用了 key idx
key: idx
key_len: 131
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
mysql> show create table user;
-- -----省略表格线-----
| user | CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`data` json DEFAULT NULL,
`user_name` varchar(32) GENERATED ALWAYS AS (json_extract(data,"$.name")) VIRTUAL,
`user_name2` varchar(32) GENERATED ALWAYS AS (json_extract(data,"$.name")) VIRTUAL,
PRIMARY KEY (`uid`),
KEY `idx` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 |
-- -----省略表格线-----
1 row in set (0.00 sec)
二. 附录
1 | -- |