MYSQL8.0-生成列(Generated Columns)基础
生成列是指值是通过表达式计算而来的列,参与表达式计算的列是已经表中已经定义的列
语法及规则
新建表时创建生成列
举个栗子:
- 想要获取两个列组合的数据
SELECT CONCAT(first_name,' ',last_name) AS full_name FROM t1;
- 但是如果full_name在多个场景中使用,那么每个使用的地方都要调用函数组合,这样会有冗余,如果组合形式调整,那么可以考虑使用MYSQL的生成列
CREATE TABLE t1 (
first_name VARCHAR(10),
last_name VARCHAR(10),
full_name VARCHAR(255) AS (CONCAT(first_name,' ',last_name))
);
创建语法说明
col_name data_type [GENERATED ALWAYS] AS (expr)
[VIRTUAL | STORED] [NOT NULL | NULL]
[UNIQUE [KEY]] [[PRIMARY] KEY]
[COMMENT 'string']
- [GENERATED ALWAYS] 起到一个标识是生成列的作用
- expr 是生成列的表达式
- [VIRTUAL | STORED] 表示的是虚拟列是怎么存储的,VIRTUAL标识的是不存储(虚拟列也支持二级索引的),STORED,插入数据和更新数据的时候更新生成列的值,生成列占用存储空间和使用索引
生成列表达式需要遵守的规则
- 表达式的结果值必须是确定的,如果不确定那就会发生错误,例如像
now(),current_user()
这种函数 - 不允许使用存储过程和函数参数
- 不允许使用变量(系统变量、用户定义变量和存储的程序局部变量)。
- 子查询语句也是不允许的
- 可以引用其他生成列,但是被引用的生成列
- 生成列不能使用
AUTO_INCREMENT
属性,也不能以含有AUTO_INCREMENT
属性的列为基础列 - 如果生成列的表达式计算的值截断或异常,创建表会报错
- 手动更新生成列的值,只能更新为
DEFAULT
生成列的使用场景有那些
- 简化和统一查询,如果多个地方需要多个列计算的结果
- 模拟函数索引
- 获取JSON中某一属性的值,用以多个地方使用
生成列的修改语法
对于生成列,表修改的语句
ADD,MODIFY,CHANGE
是允许的
- 生成列新增语法
ALTER TABLE t1
ADD COLUMN c2 INT GENERATED ALWAYS AS (c1 + 1) STORED;
- 修改列语法类型或表达式语法
ALTER TABLE t1
MODIFY COLUMN c2 TINYINT GENERATED ALWAYS AS (c1 + 5) STORED;
- 生成列没有被其他生成列引用的情况下,可以进行重命名或者删除
ALTER TABLE t1
CHANGE c2 c3 INT GENERATED ALWAYS AS (c1 + 1) STORED;
ALTER TABLE t1 DROP COLUMN c3;
- 生成列要从虚拟变成实体列,需要先删除再新增
- 先删除
ALTER TABLE t1
DROP COLUMN c2;
- 再增加
ALTER TABLE t1
ADD COLUMN c2 INT GENERATED ALWAYS AS (c1 + 1) STORED;
- 非生成列可以改成STORED类型的生成列
ALTER TABLE t1
MODIFY COLUMN c2 INT GENERATED ALWAYS AS (c1 + 1) STORED;
- STORED类型的生成列可以变成非生成列
CREATE TABLE t1 (c1 INT, c2 INT GENERATED ALWAYS AS (c1 + 1) STORED);
ALTER TABLE t1 MODIFY COLUMN c2 INT;
- 修改的列是生成列表达式中引用的列,那么修改列的默认值和名称后,生成列数据可能会受到影响
生成列的索引优化
索引也是支持生成列的,生成列的索引使用过程中,如果存在和生成列相同的查询表达式,也会被识别成生成列,使用生成列表达式
生成列的语法
CREATE TABLE t1 (f1 INT, gc INT AS (f1 + 1) STORED, INDEX (gc));
查询条件表达式如果跟生成列的表达式相同,也会被优化器推断为生成列,按照生成列优化
例如:gc列为生成列
SELECT * FROM t1 WHERE gc > 9;
SELECT * FROM t1 WHERE f1 + 1 > 9;
那么 f1+1>9
这个条件项使用后,执行计划如下
mysql> EXPLAIN SELECT * FROM t1 WHERE f1 + 1 > 9\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: range
possible_keys: gc
key: gc
key_len: 5
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
重写SQL的信息可以用show warnings\G
来获取
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select `test`.`t1`.`f1` AS `f1`,`test`.`t1`.`gc`
AS `gc` from `test`.`t1` where (`test`.`t1`.`gc` > 9)
生成列索引优化有一些注意点
- 查询表达式要能匹配到生成列,则他们生成的结果类型要一致
- 优化适用于这些操作符:
=、<、<=、>、>=、BETWEEN和IN()
。 - 生成列要包含函数使用,或者列操作。如果只是简单的引用其他列则没办法进行优化
- 生成列如果是JSON数据中的某个属性值,那么要让获取的结果类型统一,使用
JSON_UNION
函数处理
以上是对生成列的简单总结,更多可以通过阅读官方文档获取。后续在使用中,我也会逐步补充细节。
分类:
数据库
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏