深入探索MySQL的虚拟列:发展、原理与应用

当我们谈论数据库优化时,经常会遇到各种技术和策略。其中,MySQL的虚拟列(也被称为生成列或存储列)是一个引人注目的特性。它不仅可以帮助开发者提高查询效率,还能为数据表提供额外的计算功能,而无需真正改变表的结构。在这篇文章中,我们将深入探讨MySQL虚拟列的发展、原理以及应用。

一、虚拟列的发展

在早期的MySQL版本中,开发者通常需要为经常需要计算的字段创建额外的物理列,并在数据插入或更新时手动计算这些列的值。这种方法虽然可行,但它增加了数据冗余和应用程序的复杂性。

为了解决这个问题,MySQL 5.7版本引入了虚拟列(也称为生成列)的概念。虚拟列允许开发者在表中定义一个基于其他列的计算公式,而不需要实际存储这些计算的结果。当查询虚拟列时,MySQL会根据公式动态计算其值。

在后续的版本中,MySQL进一步增强了虚拟列的功能,允许开发者选择是否将虚拟列的结果实际存储在磁盘上(即存储列),以提高查询性能。

二、虚拟列的原理

虚拟列的工作原理相对简单。当你在表中定义一个虚拟列时,你需要为其提供一个表达式,该表达式基于表中的其他列。每当查询虚拟列时,MySQL都会根据该表达式动态计算其值。

虚拟列的一个重要特点是它们不占用实际的磁盘空间(除非你选择将它们定义为存储列)。这意味着你可以在不增加存储开销的情况下为表添加额外的计算功能。MySQL 5.7 并且支持两种类型的生成列:

虚拟生成列(Virtual Generated Column):

  • 虚拟生成列的值是在查询时动态计算的,不会占用额外的磁盘空间来存储这些值。
  • 它们的值是根据列定义中的表达式计算得出的,该表达式可以引用同一表中的其他列。
  • 由于值是动态计算的,因此每次查询虚拟生成列时,MySQL 都会根据相应的表达式重新计算其值。
  • 虚拟生成列可以用于 SELECT 查询的 WHERE 子句、ORDER BY 子句和 GROUP BY 子句等,以提供基于计算的查询条件或排序。

存储生成列(Stored Generated Column):

  • 存储生成列的值是在数据插入或更新时计算的,并且计算结果会实际存储在磁盘上。
  • 与虚拟生成列不同,存储生成列占用了额外的磁盘空间来存储它们的值。
  • 由于值是预先计算并存储的,因此在查询存储生成列时,MySQL 可以直接读取存储的值,而不需要重新计算。
  • 存储生成列可以用于创建索引,以进一步提高查询性能。索引可以基于存储生成列的值进行快速查找和排序。

三、虚拟列的用法

当你定义一个虚拟列时,你需要使用GENERATED ALWAYS AS语句来指定该列的值是如何从其他列计算得出的。基本的语法如下:

column_name data_type[GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED]
  • column_name:虚拟列的名称。
  • data_type:虚拟列的数据类型,它必须与你所使用的表达式返回的数据类型兼容。
  • GENERATED ALWAYS:指示该列的值总是由给定的表达式生成。- ALWAYS关键字是可选的,因为默认情况下生成列就是ALWAYS生成的。
  • AS (expression):指定如何计算虚拟列值的表达式。这个表达式可以引用表中的其他列。
  • VIRTUAL 或 STORED:指定生成列的类型。VIRTUAL表示该列的值在查询时动态计算,而STORED表示该列的值在数据插入或更新时计算并存储。如果你省略这部分,MySQL 5.7及更早版本会默认使用VIRTUAL,而在MySQL 8.0及更高版本中,你需要明确指定VIRTUAL或STORED。

我们创建一个表,其中包含一个JSON列和一个基于JSON列中某个值的虚拟列。然后,我们为这个虚拟列创建索引以提高查询性能。
首先,我们创建一个包含JSON列和虚拟列的表:

CREATE TABLE users (  id INT AUTO_INCREMENT PRIMARY KEY,  profile JSON,  full_name VARCHAR(255) GENERATED ALWAYS AS (  CONCAT(  JSON_UNQUOTE(JSON_EXTRACT(profile, '$.first_name')), ' ',  JSON_UNQUOTE(JSON_EXTRACT(profile, '$.last_name'))  )  ) VIRTUAL  
);

users 表有一个 profile 列,它的数据类型是 JSON。此外,我们还有一个 full_name 虚拟列,它是通过拼接 profile 列中 first_name 和 last_name 键对应的值生成的。我们使用 JSON_EXTRACT 函数从 profile 列中提取值,并使用 JSON_UNQUOTE 函数将提取出的JSON字符串转换为普通字符串。
接下来,我们为 full_name 虚拟列创建一个索引:

CREATE INDEX idx_full_name ON users(full_name);-- 插入数据  
INSERT INTO users (profile) VALUES  
('{"first_name": "John", "last_name": "Doe"}'),  
('{"first_name": "Jane", "last_name": "Smith"}');  -- 查询数据  
SELECT * FROM users WHERE full_name = 'John Doe';

由于我们已经为 full_name 列创建了索引,因此上述查询应该会更快,尤其是当表中有大量数据时。

请注意,由于 full_name 是一个虚拟列,你不能直接更新它的值。如果你需要改变 full_name 的值,你必须更新 profile 列中相应的 first_name 或 last_name 值。

四、虚拟列的使用条件和限制

4.1使用条件:

  • 确定性:生成列的表达式必须是确定性的。这意味着给定相同的输入,表达式必须总是产生相同的结果。例如,使用NOW()函数的表达式就不是确定性的,因为它返回当前的日期和时间。

  • 引用其他列:生成列的表达式可以引用表中的其他列,但这些列必须定义在生成列之前。

  • 数据类型兼容性:生成列的数据类型必须与表达式的结果兼容。例如,如果你将两个整数相加,生成列的数据类型应该是整数类型。

  • 索引限制:只有STORED生成列可以被索引。VIRTUAL生成列在MySQL 5.7及更早版本中不能被索引,但在MySQL 8.0及更高版本中,这个限制已经被放宽,允许对VIRTUAL生成列创建索引。

4.2 限制条件:

  • 性能考虑:对于VIRTUAL生成列,每次查询时都需要计算表达式,这可能会影响性能,尤其是当表达式复杂或数据量大时。对于STORED生成列,虽然计算只在数据插入或更新时发生,但它们占用了额外的存储空间。

  • 存储引擎限制:并非所有的MySQL存储引擎都支持生成列。例如,在MySQL 5.7中,只有InnoDB、MyISAM和MEMORY存储引擎支持生成列。

  • 表达式限制:生成列的表达式有一些限制。例如,它们不能引用其他表中的列,不能包含子查询,不能引用非确定性的函数(如RAND()或NOW()),除非这些函数被用作常量值。

  • 修改限制:一旦创建了生成列,就不能直接修改它的值。因为它是根据其他列的值自动生成的。如果你需要改变生成列的值,你必须修改它所依赖的列的值。

  • 复制和二进制日志:如果你的MySQL服务器配置了复制或使用了二进制日志,那么对生成列的更改(通过修改它所依赖的列)也会被记录并复制到其他服务器上。

  • 备份和恢复:在备份和恢复数据库时,需要确保备份工具能够正确处理生成列。一些较旧的备份工具可能不支持生成列。

  • 升级考虑:如果你的数据库是从较旧的MySQL版本升级而来的,需要确保升级过程正确处理了生成列。在升级之前,最好先在测试环境中验证生成列的行为和性能。

五、虚拟列的应用场景

虚拟列在许多场景中都非常有用。以下是一些常见的应用示例:

  • 复杂计算与表达式:当查询中需要频繁进行复杂计算,而这些计算又是基于表中其他字段的时候,虚拟列特别有用。通过将这些计算定义为虚拟列,MySQL可以预先或在查询时计算这些值,从而避免在每次查询时都重复相同的计算。

  • 用作索引:虚拟列可以被索引,这对于提高查询性能非常关键。特别是在处理大型数据集时,如果查询条件涉及到计算密集型操作,将这些操作的结果存储为虚拟列并为其创建索引可以大大加快查询速度。

  • 数据转换与格式化:如果查询中经常需要将数据从一种格式转换为另一种格式(例如日期时间格式、货币格式等),将这些转换定义为虚拟列可以减少每次查询时的转换开销。

  • 统一查询逻辑:在复杂的应用程序中,可能会有多个查询需要执行相同的计算或转换。通过使用虚拟列,可以将这些计算或转换的逻辑封装在表结构中,使得查询更加简洁且易于维护。

  • 避免使用视图:在某些情况下,开发者可能会使用视图来封装复杂的查询逻辑。然而,视图在某些情况下可能不如虚拟列高效。虚拟列允许数据库在物理表层面进行优化,而视图则可能需要在每次查询时动态生成结果集。

  • 减少IO操作:当使用存储虚拟列时(即结果实际存储在磁盘上),由于数据已经预先计算并存储,因此可以减少查询时的IO操作,从而提高查询性能。

  • 与JSON等非标准字段的交互:对于存储了JSON或其他非标准格式数据的字段,直接在这些字段上进行查询可能会非常低效。通过将JSON字段中的值提取为虚拟列,并为其创建索引,可以显著提高对这些数据的查询效率。

六、总结

MySQL的虚拟列是一个强大而灵活的特性,它允许开发者在表中定义基于其他列的计算结果,而无需实际存储这些计算的值。通过使用虚拟列,你可以避免数据冗余,简化查询,优化索引,执行数据验证以及自动转换数据格式。

随着MySQL的不断发展,我们可以期待虚拟列在未来版本中继续得到增强和优化,为开发者提供更多便利和功能。在设计和优化数据库时,不要忘记考虑使用虚拟列来提高性能和简化应用程序逻辑。

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

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

相关文章

【Linux驱动】块设备驱动(二)—— 块设备读写(使用请求队列)

块设备的操作函数并没有类似于字符驱动中的read 和write函数,要实现读写操作,只能在请求处理函数中实现。这就分为两种,是否要使用请求队列,请求队列的主要作用是管理和调度IO请求。在以下情况中,一般需要用到请求队队…

跑路页面HTML源码

简单的HTMLJSCSS,记事本修改内容,喜欢的朋友可以下载 https://download.csdn.net/download/huayula/88811984

vivado RTL综合中的多线程

RTL综合中的多线程 在多处理器系统上,RTL合成默认情况下利用多个CPU核心(最多四个)来加快编译时间。同时运行的线程的最大数量会有所不同,具体取决于处理器的数量可在系统、操作系统和流程阶段使用(请参阅Vivado Desi…

Thinkpad E550 安装 Ubuntu

参考:使用U盘安装Ubuntu20.04 Thinkpad E550 使用 enterf1进入 bios, 使用 f12 进入 boot 选项。不知道这个和系统有啥关系,感觉之前不是这样。。。 下载镜像 下载镜像 22.04 可以下载相应的 torrent 文件,然后用 百度网盘或者…

HTTP1.1、HTTP2、HTTP3

HTTP1.1 HTTP/1.1 相比 HTTP/1.0 性能上的改进: 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去&…

Linux基础-磁盘分区

1.Linux磁盘分区方案 1.根分区/ 2./boot 3./var/log 4.swap虚拟交换分区,当物理内存不够用,需要用swap 5.自定义分区: ①创建一个目录/etc/mysql装mysql数据库软件 ②再创建一个目录/backup存放mysql数据库备份文件 2.磁盘分区划分 第一个…

(22)删除指定的数

文章目录 每日一言题目解题思路代码结语 每日一言 你热爱生命吗?那就别浪费时间,因为时间是组成生命的材料。——富兰克林 题目 先输入10个整数存放在数组中,再输入一个整数n,删除数组中所有等于n的数字,打印数组中剩…

在VM虚拟机上搭建MariaDB数据库服务器

例题:搭建MariaDB数据库服务器,并实现主主复制。 1.在二台服务器中分别MariaDB安装。 2.在二台服务器中分别配置my.cnf文件,开启log_bin。 3.在二台服务器中分别创建专用于数据库同步的用户replication_user,并授权SLAVE。&#x…

Matplotlib绘制炫酷柱状图的艺术与技巧【第60篇—python:Matplotlib绘制柱状图】

文章目录 Matplotlib绘制炫酷柱状图的艺术与技巧1. 簇状柱状图2. 堆积柱状图3. 横向柱状图4. 百分比柱状图5. 3D柱状图6. 堆积横向柱状图7. 多系列百分比柱状图8. 3D堆积柱状图9. 带有误差线的柱状图10. 分组百分比柱状图11. 水平堆积柱状图12. 多面板柱状图13. 自定义颜色和样…

c#string方法对比

字符串的截取匹配操作在开发中非常常见,比如下面这个示例:我要匹配查找出来字符串数组中以“abc”开头的字符串并打印,我下面分别用了两种方式实现,代码如下: using System; namespace ConsoleApp23{ class Progra…

aidl复杂流程封装

1 aidl相关困扰点 1 制作步骤复杂,先定义然后编译,然后复制,两边都要一一对应 2 增加回调,自定义对象流程更加麻烦,还要处理对象数据流是 in 还是out。 3 一方异常怎么办,虽然服务端可以用 RemoteCallbackL…

UI自动化中元素无法定位问题解决方法

元素无法定位问题解决方法 1、display屏蔽元素2、iframe内元素无法定位3、 根据部分元素属性定位4、页面跳转到新的标签页,或者弹出的警告框等6、使用WebDriver调用JavaScript代码代替无法实现的功能 1、display屏蔽元素 分析一下html的display属性,可以…

计算机网络(复习资料)

1.互联网的两个重要基本特点 连通性和共享性 2.计算机网络由若干节点和连接这些节点的链路组成 3.有多个网络通过路由器相互连接起来,构成一个更大的计算机网络称为互联网 4.网络把许多计算机连接在一起,互联网把许多网络通过一些路由器连接在一起,与网络相连的计算机称为…

web应用课——(第五讲:React)

目录 一、配置环境 二、ES6语法补充 三、Components 四、组合Components 五、路由 六、Redux 一、配置环境 感谢z神(zst_2001)的分享: git下载与安装Node.js下载与安装React下载与安装 二、ES6语法补充 使用bind()函数绑定this取值&…

haiku实现TemplatePairStack类

TemplatePairStack是实现蛋白质结构模版pair_act特征表示的类: 通过layer_stack.layer_stack(c.num_block)(block) 堆叠c.num_block(配置文件中为2)block 函数,每个block对输入pair_act 和 pair_mask执行计算流程:TriangleAttention —> dropout ->TriangleAttentio…

Retrofit源码分析及理解

参考文档: 12W字;2022最新Android11位大厂面试专题(一) - 掘金 Retrofit 版本号:2.9.0 Retrofit简单来说,就是对OkHttp上层进行了封装,已达到用户方便使用管理网络请求的目的。 Retrofit内部有…

力扣热门100题刷题笔记 - 10. 正则表达式匹配

力扣热门100题 - 10. 正则表达式匹配 题目链接:10. 正则表达式匹配 题目描述: 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配&#xff…

asqlcell,一个超强的 Python 库!

前言 大家好,今天为大家分享一个超强的 Python 库 - asqlcell。 Github地址:https://github.com/datarho/asqlcell Python asqlcell 是一个用于执行异步数据库操作的开源库,它允许开发者通过异步的方式与数据库进行交互,提高了数…

如何使用VS Code编写小游戏并实现公网游玩本地游戏【内网穿透】

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 前言 本篇教程,我们将通过VS Code实现远程开发MENJA小游戏,并通过cpolar内网穿透发布到公网,分…

七月论文审稿GPT第2.5版:微调GPT3.5 turbo 16K和llama2 13B以扩大对GPT4的优势

前言 自去年7月份我带队成立大模型项目团队以来,我司至今已有5个项目组,其中 第一个项目组的AIGC模特生成系统已经上线在七月官网第二项目组的论文审稿GPT则将在今年3 4月份对外上线发布第三项目组的RAG知识库问答第1版则在春节之前已就绪至于第四、第…