MySQL 5.7新特性之Generated Column(函数索引)与 Oracle 的函数索引

本文介绍了MySQL 5.7中的Generated Column,包括Virtual与Stored Column的区别,以及在Generated Column上创建索引的实践。通过示例展示了Generated Column的使用,并对比了与Oracle函数索引的异同,强调了在MySQL中使用Generated Column的注意事项和限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mysql不提供函数索引的创建,mysql5.7版本之后提供Generated Column类似的功能,如:
alter table RP_RONGHE_PROXY_OPR_MER_DETAIL add column substr_through_date varchar(8) generated always as (SUBSTR(THROUGH_DATE,0,8)) VIRTUAL; 在该字段上创建联合索引:
alter table RP_RONGHE_PROXY_OPR_MER_DETAIL add key IDX$RONGHE$DATE$status(substr_through_date,mcht_status);

MySQL 5.7引入了Generated Column,这篇文章简单地介绍了Generated Column的使用方法和注意事项,为读者了解MySQL 5.7提供一个快速的、完整的教程。这篇文章围绕以下几个问题展开: 

Generated Column是什么 
Virtual Column与Stored Column的区别 
如果我对Generated Column做一些破坏行为会怎么样 
Generated Column上创建索引 
Generated Column上创建索引与Oracle的函数索引的区别 

Generated Column是什么 

Generated Column是MySQL 5.7引入的新特性,所谓Cenerated Column,就是数据库中这一列由其他列计算而得,我们以官方参考手册中的例子予以说明。 


例如,知道直角三角形的两条直角边,要求斜边的长度。很明显,斜边的长度可以通过两条直角边计算而得,那么,这时候就可以在数据库中只存放直角边,斜边使用Generated Column,如下所示: 

CREATE TABLE triangle ( 
sidea DOUBLE, 
sideb DOUBLE, 
sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb))); 

INSERT INTO triangle (sidea, sideb) VALUES(1,1),(3,4),(6,8); 

查询结果: 

mysql> SELECT * FROM triangle; 
+-------+-------+--------------------+ 
| sidea | sideb | sidec | 
+-------+-------+--------------------+ 
| 1 | 1 | 1.4142135623730951 | 
| 3 | 4 | 5 | 
| 6 | 8 | 10 | 
+-------+-------+--------------------+ 

这个例子就足以说明Generated Columns是什么,以及怎么使用用了。 


Virtual Generated Column与Stored Generated Column的区别 

在MySQL 5.7中,支持两种Generated Column,即Virtual Generated Column和Stored Generated Column,前者只将Generated Column保存在数据字典中(表的元数据),并不会将这一列数据持久化到磁盘上;后者会将Generated Column持久化到磁盘上,而不是每次读取的时候计算所得。很明显,后者存放了可以通过已有数据计算而得的数据,需要更多的磁盘空间,与Virtual Column相比并没有优势,因此,MySQL 5.7中,不指定Generated Column的类型,默认是Virtual Column。此外: 
Stored Generated Column性能较差,见这里 
如果需要Stored Generated Golumn的话,可能在Generated Column上建立索引更加合适,见本文第4部分的介绍 

综上,一般情况下,都使用Virtual Generated Column,这也是MySQL默认的方式,如果使用Stored Generated Column,前面的建表语句将会是下面这样,即多了一个stored关键字: 

Create Table: CREATE TABLE `triangle` ( 
 `sidea` double DEFAULT NULL, 
 `sideb` double DEFAULT NULL, 
 `sidec` double GENERATED ALWAYS AS (SQRT(sidea * sidea + sideb * sideb)) STORED) 
 

如果对generated column做一些破坏行为会怎么样? 

我们已经知道了generated column是什么,并且知道了如何使用generated column,为了避免误用,我们先来进行一些实验,以免在具体使用时出现一些未知的情况。 

将generated column定义为 "除以0" 

如果我们将generated column定义为 "x列 / 0",MySQL并不会直接报错,而是在插入数据时报错,并提示"ERROR 1365 (22012): Division by 0" 
 
mysql> create table t( x int, y int, z int generated always as( x / 0)); 
Query OK, 0 rows affected (0.22 sec) 
 
mysql> insert into t(x,y) values(1,1); 
ERROR 1365 (22012): Division by 0 


插入恶意数据 
如果我们将generated column定义为 "x列/y列",在插入数据,如果y列为0的话,同样提示错误,如下所示: 

mysql> create table t( x int, y int, z int generated always as( x / y)); 
Query OK, 0 rows affected (0.20 sec) 

mysql> insert into t(x,y) values(1,0); 
ERROR 1365 (22012): Division by 0 
 

删除源列 
 
如果我们将generated column定义为 "x列/y列",并尝试删除x列或y列,将提示"ERROR 3108 (HY000): Column 'x' has a generated column dependency." 

mysql> create table t( x int, y int, z int generated always as( x / y)); 
Query OK, 0 rows affected (0.24 sec) 

mysql> alter table t drop column x; 
ERROR 3108 (HY000): Column 'x' has a generated column dependency. 
 

定义显然不合法的Generated Column 
 
如果我们将generated column定义为 "x列+y列",很明显,x列或y列都是数值型,如果我们将x列或y列定义(或修改)为字符型(当然,实际使用时应该不会有人傻到这样去做),则预期会报错,然而并没有,如下所示,我们可以正常创建。 

 mysql> create table t( x int, y varchar(100), z int generated always as( x + y)); 
 Query OK, 0 rows affected (0.13 sec) 

并且插入如下这样的数据也不会出错: 

mysql> insert into t(x,y) values(1,'0'); 
Query OK, 1 row affected (0.01 sec) 

mysql> select * from t; 
+------+------+------+ 
| x | y | z | 
+------+------+------+ 
| 1 | 0 | 1 | 
+------+------+------+ 
1 row in set (0.00 sec) 

但是对于MySQL无法处理的情况,则会报错: 

mysql> insert into t(x,y) values(1,'x'); 
ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'x' 

Generated Column上创建索引 

同样,我们可以在generated column上建立索引,建立索引以后,能够加快查找速度,如下所示: 

mysql> create table t(x int primary key, y int, z int generated always as (x / y), unique key idz(z)); 
Query OK, 0 rows affected (0.11 sec) 

mysql> show create table t\G 
*************************** 1. row *************************** 
Table: t 
Create Table: CREATE TABLE `t` (
  `x` int(11) NOT NULL,
  `y` int(11) DEFAULT NULL,
  `z` int(11) GENERATED ALWAYS AS (x / y) VIRTUAL,
  PRIMARY KEY (`x`),
  UNIQUE KEY `idz` (`z`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 
1 row in set (0.01 sec) 

 
并且,我们可以创建普通索引和唯一索引,如果是唯一索引,在违反了唯一性约束时,进行报错: 

mysql> insert into t(x,y) values(1,1); 
Query OK, 1 row affected (0.02 sec) 

mysql> insert into t(x,y) values(2,2); 
ERROR 1062 (23000): Duplicate entry '1' for key 'idz' 

 
所以,在使用MySQL5.7时,还需要对Generated Column有所了解,才能够解决一些以前没有遇到过的问题。 
 
索引的限制 
虽然一般情况下都应该使用Virtal Generated Column,但是,目前使用Virtual Generated Column还有很多限制,包括: 

 
聚集索引不能包含virtual generated column 

mysql> create table t1(a int, b int , c int GENERATED ALWAYS AS (a / b), primary key(c)); 
ERROR 3106 (HY000): 'Defining a virtual generated column as primary key' is not supported for generated columns. 

mysql> create table t1(a int, b int , c int GENERATED ALWAYS AS (a / b) STORED, primary key(c)); 
Query OK, 0 rows affected (0.11 sec) 

不能在Virtual Generated Column上创建全文索引和空间索引,这个在之后的MySQL版本中有望解决(Inside君咋记得Stored Column上市可以的呢?)。 

Virtual Generated Column不能作为外键 

创建generated column(包括virtual generated column 和stored generated column)时不能使用非确定性的(不可重复的)函数 

mysql> ALTER TABLE `t1` ADD p3 DATE GENERATED ALWAYS AS (curtime()) virtual; 
ERROR 3102 (HY000): Expression of generated column 'p3' contains a disallowed function. 

mysql> ALTER TABLE `t1` ADD p3 DATE GENERATED ALWAYS AS (curtime()) stored; 
ERROR 3102 (HY000): Expression of generated column 'p3' contains a disallowed function. 

 


Generated Column上创建索引与Oracle的函数索引的区别 
介绍完MySQL在Generated Column上的索引,熟悉Oracle的同学这时候可能会想起Oracle的函数索引,在MySQL的Generated Column列上建立索引与Oracle的函数索引比较类似,又有所区别: 

例如有一张表,如下所示: 

mysql> CREATE TABLE t1 (first_name VARCHAR(10), last_name VARCHAR(10)); 
Query OK, 0 rows affected (0.11 sec) 

假设这时候需要建一个full_name的索引,在Oracle中,我们可以直接在创建索引的时候使用函数,如下所示: 

alter table t1 add index full_name_idx(CONCAT(first_name,' ',last_name)); 

但是,上面这条语句在MySQL中就会报错。在MySQL中,我们可以先新建一个Generated Column,然后再在这个Generated Column上建索引,如下所示: 

mysql> alter table t1 add column full_name VARCHAR(255) GENERATED ALWAYS AS (CONCAT(first_name,' ',last_name)); 

mysql> alter table t1 add index full_name_idx(full_name); 

乍一看,MySQL需要在表上增加一列,才能够实现类似Oracle的函数索引,似乎代价会高很多。但是,我们在第2部分说过,对于Virtual Generated Column,MySQL只是将这一列的元信息保存在数据字典中,并不会将这一列数据持久化到磁盘上,因此,在MySQL的Virtual Generated Column上建立索引和Oracle的函数索引类似,并不需要更多的代价,只是使用方式有点不一样而已。 


<think>好的,我现在需要帮用户解析JSON格式的报文,里面包含code、data、msg字段,还有date、meter_status、balance等详细信息。首先,我得回忆一下不同数据库处理JSON的方法,因为用户提到了MySQL、SQL Server和Oracle的引用内容。 首先,用户引用了MySQL解析JSON的方法,版本5.7之后支持JSON类型,可以用JSON_EXTRACT或者->操作符。那在MySQL里,提取code和msg应该不难,比如用`data->'$.code'`这样的语法。然后data字段里的详细信息可能需要嵌套提取,比如date可能在data里面,所以可能需要`data->'$.data.date'`这样的路径。不过要注意MySQL的JSON路径语法是否正确。 接下来是SQL Server,用户提到用JSON_VALUE和JSON_MODIFY。SQL Server处理JSON用的是这些函数,所以提取code的话应该是`JSON_VALUE(json_column, '$.code')`,而嵌套的字段比如meter_status可能需要更深的路径,比如`JSON_VALUE(json_column, '$.data.meter_status')`。不过需要确认SQL Server是否支持多级路径的解析。 然后是Oracle,12.1.0.2版本之后支持JSON,可以用JSON_TABLE或者简单的点号语法。例如,`json_column.data.date`这样的方式,或者用JSON_TABLE来展开成表格形式。不过Oracle的语法可能和其他数据库不同,需要特别注意验证JSON的有效性,比如用IS_JSON函数。 用户的需求是分析报文结构和内容,所以可能需要先确定使用哪种数据库,因为不同数据库的解析方法不同。但用户没有明确说,可能需要给出通用的方法,或者分别说明不同数据库的处理方式。 另外,用户提供的示例引用中有提到验证JSON数据,比如Oracle的IS_JSON,这可能需要在插入数据前检查格式是否正确,避免解析错误。所以在实际处理中,应该先验证JSON的有效性。 接下来,用户可能需要具体的SQL示例来提取各个字段。比如在MySQL中,提取code、msg、date、meter_status、balance这些字段,可能需要多级的JSON_EXTRACT调用。在SQL Server中则是用JSON_VALUE函数嵌套。而Oracle可能用JSON_TABLE来转换成列。 还需要注意性能问题,比如在MySQL中为JSON字段添加索引,或者SQL Server中的计算列加索引,以提高查询效率。用户可能关心如何高效地查询这些JSON字段,特别是在大数据量的情况下。 另外,用户的问题中提到的报文结构可能是一个嵌套的JSON,比如data字段本身也是一个对象,里面包含date、meter_status、balance等。所以需要正确指定JSON路径来访问嵌套字段。 最后,是否需要考虑不同数据库的兼容性?比如如果用户需要跨数据库的解决方案,可能需要使用通用的方法,或者分别处理。但根据引用内容,用户可能已经使用了其中一种数据库,所以需要分别给出不同数据库的解决方案。 总结步骤: 1. 分析JSON结构,确定字段路径。 2. 根据使用的数据库选择对应的解析函数。 3. 编写SQL语句提取所需字段。 4. 验证JSON格式有效性。 5. 考虑性能优化,如添加索引。</think>根据JSON报文结构特点,我将分步骤说明不同数据库的解析方法: ### 一、JSON报文结构分析 假设报文结构如下: ```json { "code": 200, "msg": "success", "data": { "date": "2023-08-15", "meter_status": 1, "balance": 150.50 } } ``` ### 二、MySQL解析方法 1. **基础字段提取**: ```sql SELECT JSON_EXTRACT(json_column, '$.code') AS code, JSON_EXTRACT(json_column, '$.msg') AS msg FROM table_name; ``` 2. **嵌套字段提取**: ```sql SELECT json_column->'$.data.date' AS date, json_column->'$.data.meter_status' AS status, json_column->'$.data.balance' AS balance FROM table_name WHERE json_column->'$.code' = '200'; ``` 3. **创建虚拟列优化查询**: ```sql ALTER TABLE table_name ADD balance_value DECIMAL(10,2) GENERATED ALWAYS AS (json_column->'$.data.balance'); ``` [^1] ### 三、SQL Server解析方法 ```sql SELECT JSON_VALUE(json_column, '$.code') AS code, JSON_VALUE(json_column, '$.data.date') AS date, JSON_QUERY(json_column, '$.data') AS full_data FROM table_name WHERE ISJSON(json_column) = 1; -- 验证JSON格式有效性[^2] ``` ### 四、Oracle解析方法 1. **使用JSON_TABLE展开数据**: ```sql SELECT jt.* FROM table_name t, JSON_TABLE(t.json_column, '$' COLUMNS ( code NUMBER PATH '$.code', msg VARCHAR2(50) PATH '$.msg', NESTED PATH '$.data' COLUMNS ( date DATE PATH '$.date', status NUMBER PATH '$.meter_status', balance NUMBER PATH '$.balance' ) ) ) jt; ``` 2. **直接路径访问**: ```sql SELECT json_column.code, json_column.data.date FROM table_name WHERE json_column.data.meter_status = 1; [^3] ``` ### 五、通用验证建议 1. 插入数据前使用`ISJSON()`验证格式(SQL Server/Oracle) 2. 对高频查询字段创建函数索引 3. 使用`JSON_VALID()`检查数据完整性(MySQL) 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值