MySQL虚拟列及json优化
Posted _雪辉_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL虚拟列及json优化相关的知识,希望对你有一定的参考价值。
一、虚拟列
1.1 什么是虚拟列
在mysql 5.7中,支持两种Generated Column,即Virtual Generated Column和Stored Generated Column,前者只将Generated Column保存在数据字典中,并不会将这一列数据持久化到磁盘上;后者会将虚拟列持久化到磁盘上,而不是每次读取的时候计算所得。后者存放了可以通过已有数据计算而得的数据,需要更多的磁盘空间,与Virtual Column相比并没有优势,因此,MySQL 5.7中,不指定Generated Column的类型,默认是Virtual Column。
- Virtual Column:列值不存储在磁盘上,而是在读取行时,在任何BEFORE触发器之后立即计算
- Stored Column:在插入或更新行时计算并存储列值。存储的列需要额外存储空间
语法
col_name data_type [GENERATED ALWAYS] AS (expr)
[VIRTUAL | STORED] [NOT NULL | NULL]
[UNIQUE [KEY]] [[PRIMARY] KEY]
[COMMENT 'string']
CREATE TABLE t1 (c1 INT, c2 INT GENERATED ALWAYS AS (c1 + 1) STORED);
ALTER TABLE t1 CHANGE c2 c3 INT GENERATED ALWAYS AS (c1 + 1) STORED;
ALTER TABLE t1 DROP COLUMN c3;
1.2 虚拟列限制
- 允许使用文本、确定性内置函数和运算符。如果给定表中相同的数据,多个调用独立于连接的用户,则函数是确定性的。非确定性且未通过此定义的函数示例:CONNECTION_ID()、CURRENT_USER()、NOW()。
- 不允许存储函数和用户定义的函数。
- 不允许存储过程和函数参数。
- 不允许变量(系统变量、用户定义变量和存储程序局部变量)。
- 不允许子查询。
- 生成的列定义可以指代其他生成的列,但只能指表定义中较早发生的列。生成的列定义可以引用表中的任何基列(无能)列,无论其定义发生在更早还是更晚。
- AUTO_INCREMENT属性不能用于生成的列定义。
- AUTO_INCREMENT列不能用作生成列定义中的基础列。
- Virtual Generated Column不能更改为Stored Generated Column
- 非虚拟列可以转换为Stored Generated Column,同样Stored Generated Column也可以转换为非虚拟列
二、使用虚拟列对json类型进行优化
root@localhost 17:19: [sbtest]> show create table users;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| users | CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`doc` json DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
root@localhost 17:19: [sbtest]> select * from users;
+----+--------------------------------+
| id | doc |
+----+--------------------------------+
| 1 | {"age": 28, "name": "big_cat"} |
| 2 | {"age": 29, "name": "james"} |
+----+--------------------------------+
2 rows in set (0.01 sec)
root@localhost 17:30: [sbtest]> explain select id, user->"$.age" from users where json_extract(user, "$.name") = "xuehui";
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | users | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
root@localhost 17:30: [sbtest]> select id, user->"$.age" from users where json_extract(user, "$.name") = "xuehui";
+----+---------------+
| id | user->"$.age" |
+----+---------------+
| 1 | 24 |
+----+---------------+
1 row in set (0.00 sec)
root@localhost 17:32: [sbtest]> alter table `users` add column `user_name` varchar(10) generated always as (`user`->"$.name");
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
root@localhost 17:32: [sbtest]> alter table `users` add index `index_u_n`(`user_name`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
root@localhost 17:42: [sbtest]> select id, user->"$.name" from users where user_name = "\\"xuehui\\"";
+----+----------------+
| id | user->"$.name" |
+----+----------------+
| 1 | "xuehui" |
+----+----------------+
1 row in set (0.00 sec)
root@localhost 17:42: [sbtest]> explain select id, user->"$.name" from users where user_name = "\\"xuehui\\"";
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | users | NULL | ref | index_u_n | index_u_n | 43 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
以上是关于MySQL虚拟列及json优化的主要内容,如果未能解决你的问题,请参考以下文章
如何优化使用 PHP 或 Mysql 或 Laravel 将 12K 的 JSON 插入数据库