5千字总结冷门的MySQL虚拟字段(虚拟列)

news/2025/3/25 21:24:12/文章来源:https://www.cnblogs.com/phpphp/p/18788610

MySQL虚拟字段,因不是必用且耗算力。所以是冷门的存在,很多开发者都会忽略它。当然存在就有价值,花时间整理了相关知识点。

MySQL虚拟字段(或叫虚拟列)

  • 官方文档:https://dev.mysql.com/doc/refman/8.0/en/create-table-generated-columns.html
  • 极简概括:一种特殊字段,它们的值不是直接存储在表中,而是在查询时根据所填写表达式(或结合其它字段)计算出来。关于虚拟字段的操作,属于DDL。
  • 解决问题:在数据生成时,通过表达式动态生成数据,方便展示与免去客户端调用时的计算。
  • 使用场景:当需要直观展示单个或多个字段的动态计算结果。
  • 优点:
    • 虚拟列(VIRTUAL)类型不占用空间,亲测可支持索引,可以用于 WHERE 条件,提高查询灵活性。
    • 存储列(STORED)可以创建索引,相比于VIRTUAL消耗更少的算力,提高查询性能。
  • 缺点:
    • 计算开销:VIRTUAL每次查询都会实时计算。
    • 版本限制:需要 MySQL 5.7+ 版本才支持虚拟字段。
  • 分类:
    • 虚拟列(VIRTUAL):列值不存储,但在读取行时(在任何 BEFORE触发器之后)立即进行计算,虚拟列不占用存储空间,亲测支持被索引。
    • 存储列(STORED):插入或更新行时计算。存储的列需要存储空间,支持被索引。

  • 语法
    GENERATED ALWAYS表示该列的值总是根据其他列的计算结果自动生成,而不是手动插入或更新。
ALTER TABLE `表名` ADD COLUMN `虚拟字段名` 值类型 GENERATED ALWAYS AS (表达式) VIRTUAL或STORED NOT NULL;
  • 这里有一张测试表
CREATE TABLE `test` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表主键id',`num` int NOT NULL COMMENT '存储数字',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  • 添加虚拟字段,用于比num字段 + 1
ALTER TABLE `test` ADD COLUMN `num_v` int GENERATED ALWAYS AS (num + 1) VIRTUAL NOT NULL AFTER `num`;
  • 新增两条数据
INSERT INTO `test` (`num`) VALUES (1)
INSERT INTO `test` (`num`) VALUES (2)
  • 查询得出如下值
id	num	num_v
1	1	2
2	2	3

ALTER TABLE `表名`  DROP COLUMN `虚拟字段名称`;

ALTER TABLE `表名` MODIFY COLUMN `虚拟字段` int GENERATED ALWAYS AS (表达式) VIRTUAL或STORED NOT NULL;

show create table 表名
desc 表名

虚拟字段使用约束

  • 允许使用文字、确定性内置函数和运算符。如果给定表中的相同数据,多次调用会产生相同的结果(与连接的用户无关),则该函数是确定性的。非确定性且不符合此定义的函数示例: CONNECTION_ID()、 CURRENT_USER(), NOW()。
  • 不允许使用存储函数和可加载函数。
  • 不允许使用存储过程和函数参数。
  • 不允许使用变量(系统变量、用户定义变量和存储的程序局部变量)。
  • 不允许使用子查询。
  • 生成列定义可以引用其他生成列,但只能引用表定义中较早出现的列。生成列定义可以引用表中的任何基础(非生成)列,无论其定义发生的时间早晚。
  • 该AUTO_INCREMENT属性不能在生成的列定义中使用。
  • 在生成的列定义中,不能将列AUTO_INCREMENT用作基列。
  • 如果表达式计算导致截断或向函数提供不正确的输入,则 CREATE TABLE语句将以错误终止并且 DDL 操作被拒绝。
  • 存储生成列上的外键约束不能使用 CASCADE、SET NULL或 SET DEFAULT作为ON UPDATE 参照动作,也不能使用SET NULL 或SET DEFAULT作为ON DELETE参照动作。
  • 存储生成列的基列上的外键约束不能使用CASCADE、 SET NULL或SET DEFAULT 作为ON UPDATE或ON DELETE 引用操作。
  • 外键约束不能引用虚拟生成列。
  • 触发器不能使用或用来引用生成的列。 NEW.col_nameOLD.col_name
  • 对于INSERT、 REPLACE和 UPDATE,如果明确插入、替换或更新生成的列,则唯一允许的值为DEFAULT。
  • 视图中的生成列被视为可更新,因为可以为其赋值。但是,如果明确更新此类列,则唯一允许的值是 DEFAULT。

虚拟、生成字段对索引的支持

  • 先说结论:STORED类型有存储的文件实体,因此可以添加索引,而VIRTUAL类型的没有文件实体,但是也支持索引。
  • 论证:
建表
CREATE TABLE `test` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表id',`str` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '测试用字符串',`str_reverse_v` varchar(20) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (reverse(`str`)) VIRTUAL NOT NULL COMMENT '反转字符串,虚拟字段',`str_upper_s` varchar(20) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (upper(`str`)) STORED NOT NULL COMMENT '大写,生成字段',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;新增两条数据
INSERT INTO `test` (`str`) VALUES ('abc');
INSERT INTO `test` (`str`) VALUES ('xyz');尝试将两个虚拟字段添加索引,没发现报错
ALTER TABLE `test` ADD INDEX(`str_reverse_v`), ADD INDEX(`str_upper_s`);用explain分析,发现确实用到了索引
explain SELECT str_reverse_v FROM `test` where str_reverse_v = 'mn';
id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	filtered	Extra
1	SIMPLE	test		ref	str_reverse_v	str_reverse_v	82	const	1	100.00	Using indexexplain SELECT str_upper_s FROM `test` where str_upper_s = 'mn';
id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	filtered	Extra
1	SIMPLE	test		ref	str_upper_s	str_upper_s	82	const	1	100.00	Using index

常见用法举例

  • 格式化数字IP为标准IPv4地址格式
CREATE TABLE `test` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表主键id',`ip` bigint NOT NULL DEFAULT '0' COMMENT 'IPV4 数字格式',`ip_v` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (inet_ntoa(`ip`)) STORED NOT NULL COMMENT 'IPV4 字符串格式',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `test` (`ip`) VALUES (2130706433);
INSERT INTO `test` (`ip`) VALUES (3232235776);select * from testid	ip	        ip_v
1	2130706433	127.0.0.1
2	3232235776	192.168.1.0
  • JSON数据提取
CREATE TABLE `test` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表主键id',`user_info` json NOT NULL COMMENT '用户信息',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;假设要插入一条多层级的json数据,如下
{"name": "张三","gender": "男","age": 8,"birthplace": "北京市","occupation": "学生","hobbies": ["打篮球","读书"],"contact": {"phone": "18888888888","email": "zhangsan@example.com"},"examination": [{"subject": "语文","score": 80},{"subject": "数学","score": 80},{"subject": "英文","score": 80}]
}INSERT INTO `test` (`id`, `user_info`) VALUES (1, '{\"age\": 8, \"name\": \"张三\", \"gender\": \"男\", \"contact\": {\"email\": \"zhangsan@example.com\", \"phone\": \"18888888888\"}, \"hobbies\": [\"打篮球\", \"读书\"], \"birthplace\": \"北京市\", \"occupation\": \"学生\", \"examination\": [{\"score\": 80, \"subject\": \"语文\"}, {\"score\": 80, \"subject\": \"数学\"}, {\"score\": 80, \"subject\": \"英文\"}]}');可需求是就像查看这个学生考了哪些科目,其它数据都不重要
此时就需要定向取值,若取单条,可用
SELECT json_unquote(json_extract(`user_info`,_utf8mb4'$.examination[*].subject')) as subjects FROM `test`若是多条,可以新建一个虚拟字段,可以很直观的展示考取了哪些科目
ALTER TABLE `test` 
ADD COLUMN `subjects` json AS (json_unquote(json_extract(`user_info`,_utf8mb4'$.examination[*].subject'))) STORED NOT NULL AFTER `user_info`;select id, subjects from test
id	subjects
1	["语文", "数学", "英文"]
  • 日期格式化(需注意时区)
CREATE TABLE `test` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表id',`timestamp` int(11) NOT NULL COMMENT '时间戳',`date_time` datetime GENERATED ALWAYS AS (from_unixtime(`timestamp`)) STORED COMMENT '格式化时间戳 存储字段',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `test` (`timestamp`) VALUES (1700000000);select * from testid	timestamp	date_time
1	1700000000	2023-11-15 06:13:20
  • 状态判断
CREATE TABLE `test` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表id',`age` int(11) NOT NULL COMMENT '年龄',`age_v` varchar(2) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS ((case when (`age` < 12) then '儿童' when (`age` between 12 and 18) then '少年' when (`age` between 19 and 40) then '青年' when (`age` between 41 and 60) then '壮年' else '老年' end)) STORED NOT NULL COMMENT '年龄可视化判断',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `test` (`age`) VALUES (11);
INSERT INTO `test` (`age`) VALUES (16);
INSERT INTO `test` (`age`) VALUES (25);
INSERT INTO `test` (`age`) VALUES (53);
INSERT INTO `test` (`age`) VALUES (65);SELECT * FROM testid	age	age_v
1	11	儿童
2	16	少年
3	25	青年
4	53	壮年
5	65	老年

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/904453.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文速通Python并行计算:01 Python多线程编程-基本概念、切换流程、GIL锁机制和生产者与消费者模型

多线程允许程序同时执行多个任务,提升效率和响应性。线程分为新建、就绪、运行、阻塞和死亡五种状态。Python的GIL锁限制多线程并行执行,适合I/O密集型任务。生产者-消费者模型通过共享缓冲区和条件变量实现线程协作,解决数据共享问题。一文速通 Python 并行计算:01 Python…

Spring的三级缓存详解

目录 1、什么是三级缓存 2、三级缓存详解Bean实例化前属性赋值/注入前初始化后总结3、怎么解决的循环依赖 4、不用三级缓存不行吗 5、总结 一、什么是三级缓存 就是在Bean生成流程中保存Bean对象三种形态的三个Map集合,如下:

20244207 实验一 《python程序设计》实验报告

# 20244207 2024-2025-2 《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2442 姓名: 赵文萱 学号:20244207 实验教师:王志强 实验日期:2025年3月18日 必修/选修: 公选课 1.实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能; 3.编写程序,…

20244202 《Python程序设计》实验一报告

20244202 《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2442 姓名: 陈艺豪 学号:20244219 实验教师:王志强 实验日期:2025年3月23日 必修/选修: 公选课 1.实验内容 (1).熟悉Python开发环境; (2).练习Python运行、调试技能; (3).编写程序,练习变量和类…

USTCPC 2025 游记

队名 合肥一中能不能多请点OI教练,二人队。队长 @包涵宇 ,省队爷。 Day -inf~0 随机写了几道有意思的 cf 。 bhy 又在做黑的插头 dp 。膜拜。 Day 1 早上被父母逼着学习文化课,结果作业做不完直接半红温状态,, 加上昨天做了 ~8h 文化课作业只完成了 1/2 ,然后直接不做了…

AI运维助手-LinuxAgent

介绍 LinuxAgent是基于LLM大模型的智能运维助手,通过接入DeepSeek API实现对Linux终端的自然语言控制,可以实现高效的运维工作。目前已经更新到2.0.5版本。 LinuxAgent能够理解用户的自然语言指令,只要描述需求,系统自动解析意图并执行,支持中文、英语等,可以理解复杂的多…

微服务Elasticsearch

Elasticsearch中倒排索引 为什么查询效率高 比如说一个商品 在一百万条数据中 你如果要搜的话 他会从一百万条数据中去寻找 比如说你要搜小米手机 但是倒排索引是这样的 //倒排 { "小米": [1], "手机": [1,2,3,4], } 他在给定的文档范围内去搜索 比如说正…

20242825 2024-2025-2 《网络攻防实践》第四周作业

@目录一. 实验内容1.1 实验内容概述1.2 实验相关知识概述二. 实验过程2.1 ARP缓存欺骗攻击2.1.1 实验环境配置2.1.2 连通性测试2.1.3 继续实验实验亮点出现问题检查问题解决问题2.2 ICMP重定向攻击2.2.1 实验环境配置2.2.2 连通性测试发现问题检查问题解决问题2.2.3 继续实验…

论文解读-Advances in 3D Generation: A Survey

论文介绍 题目: Advances in 3D Generation: A Survey 发表年份是 2024年,综述性质的文章,是看到腾讯发布了混元3D大模型所以来看看这个论文主要贡献 论文主要根据当前研究领域内不同的3D资产的生成方法进行了一个分类,将3D生成算法分为:前馈生成,基于优化的生成,基于过…

大数据技术

Hadoop Hadoop是一个能够对大量数据进行分布式处理的软件框架 HDFS ​ HDFS(Hadoop Distributed File System,Hadoop的分布式文件管理系统),是Hadoop的两大核心之一,用于管理数据和文件 Hadoop安装 ​ Hadoop可以在Window系统上运行,但其官方支持的操作系统只有Liunx,所以…

User\main.c(7): error: #5: cannot open source input file ds18b02.h: No such file or directory

报错截图解决途径 复制报错信息上网搜索,一般的解决办法:在c/c++选项中的Include Paths中包含头文件,将移植过来的代码放到指定的文件夹里,在Floder Setup中设置新移植的文件路径。很可惜我确认过我包含了头文件,但仍然报同样错误。 最后发现我代码里面是 #include"d…