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优化的主要内容,如果未能解决你的问题,请参考以下文章

代码优化 Android json 和 mysql

Mysql查询通过其id从其他表中获取所有列及其子内容

如何优化使用 PHP 或 Mysql 或 Laravel 将 12K 的 JSON 插入数据库

优化 C# 代码片段、ObservableCollection 和 AddRange

json 个人的vscode的代码片段

实用代码片段将json数据绑定到html元素 (转)