MySQL特性 - 表属性上的表达式 - 如何计算和存储

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: MySQL从5.7版本开始支持Generated Column, 并在最近的8.0版本中支持了Functional index, 这两个特性都通过创建使用表达式进行描述的列来实现的。笔者之前满好奇这些表达式信息都是怎么存储的,本文主要记录了涉及到的相关函数,主要是做个笔记,不会深入解读。

MySQL从5.7版本开始支持Generated Column, 并在最近的8.0版本中支持了Functional index, 以及default值支持表达式, 这几个特性都通过创建使用表达式进行描述的列来实现的。笔者之前满好奇这些表达式信息都是怎么存储的,本文主要记录了涉及到的相关函数,主要是做个笔记,不会深入解读。

本文以Generated Column为例进行描述,代码基于8.0.15

使用

我们创建一个简单的表,表上包含两种类型的generated column:物理存储和虚拟列;并在虚拟列上创建索引

root@information_schema 05:38:49>show create table test.t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `a` int(11) NOT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `v1` int(11) GENERATED ALWAYS AS ((`a` + `b`)) VIRTUAL,
  `g1` int(11) GENERATED ALWAYS AS ((`a` * `v1`)) STORED,
  PRIMARY KEY (`a`),
  KEY `v1` (`v1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

root@information_schema 05:40:58>SELECT * FROM INNODB_VIRTUAL WHERE table_id = (SELECT TABLE_ID FROM INNODB_TABLES WHERE NAME LIKE 'test/t1')\G
*************************** 1. row ***************************
TABLE_ID: 1354
     POS: 65539
BASE_POS: 0
*************************** 2. row ***************************
TABLE_ID: 1354
     POS: 65539
BASE_POS: 1
2 rows in set (0.00 sec)

root@information_schema 05:41:04>

POS值实际上是一个encode的值,所以看起来很大,他包含了virtual column的序列和在所有列上的序列:

((nth virtual generated column for the InnoDB instance + 1) << 16)
+ the ordinal position of the virtual generated column

如上例,column v1, (0 + 1) << 16 + 3 = 65539

Generated column的表达式信息可以通过i_s表来查询:

root@information_schema 06:15:09>SELECT COLUMN_NAME, ORDINAL_POSITION,COLUMN_TYPE,EXTRA, GENERATION_EXPRESSION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME LIKE 't1';
+-------------+------------------+-------------+-------------------+-----------------------+
| COLUMN_NAME | ORDINAL_POSITION | COLUMN_TYPE | EXTRA             | GENERATION_EXPRESSION |
+-------------+------------------+-------------+-------------------+-----------------------+
| a           |                1 | int(11)     |                   |                       |
| b           |                2 | int(11)     |                   |                       |
| c           |                3 | int(11)     |                   |                       |
| g1          |                5 | int(11)     | STORED GENERATED  | (`a` * `v1`)          |
| v1          |                4 | int(11)     | VIRTUAL GENERATED | (`a` + `b`)           |
+-------------+------------------+-------------+-------------------+-----------------------+
5 rows in set (0.00 sec)

相关代码

存储表达式

和其他元数据信息一样, 表达式也以字符串的形式存储到mysql库下面的columns表中,注意这个表是隐藏的,你只能通过information_schame.columns来查询。
系统掉定义在文件定义在文件sql/dd/impl/tables/columns.h中
ref: dd::Column_impl::store_attributes

读取表达式

通过dd接口(dd::Column_impl::restore_attributes),存储于系统表的表达式字符串被读取出来,并被存储到TABLE_SHARE的field成员的gcol_info中,类型为类型为Value_generator, 字符串存储于类型为Value_generator::expr_str中
ref: fill_column_from_dd

当会话打开自己的TABLE对象时,会基于上述的字符串信息构建item树,存储于自己的Value_generator的item树中。
ref: open_table_from_share --> unpack_value_generator

show create table时,通过TABLE对象,从generated column列的gcol_info中中构建出表达式信息
ref: store_create_info()

读和更新表达式

当generated column需要被更新时(TABLE::is_field_used_by_generated_columns),或者产生新的插入时,需要计算其结果值
ref: update_generated_write_fields()

当读取列时,如果virtual generated column, 需要去计算其真正的值. 当然如果virtual column上创建了innodb索引,实际上其值是被存储到物理索引上的,那么就无需去计算列值
ref: update_generated_read_fields()

InnoDB内计算表达式
当InnoDB选择使用virtual column上的索引来进行查询时,如果需要读取之前的版本,需要sec record和clust record检查是否匹配时(row_sel_sec_rec_is_for_clust_rec), 也需要基于clust record,根据表达式去构建出virtual column的值,这时候就需要去回调server层的计算函数,因为clust record中并不存在virtual column的值, 相应堆栈:

row_search_mvcc
|--> Row_sel_get_clust_rec_for_mysql::operator()
    |--> row_sel_sec_rec_is_for_clust_rec
        |--> innobase_get_computed_value
            |-->  handler::my_eval_gcolumn_expr

参考文档:

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
4月前
|
SQL 监控 关系型数据库
MySQL事务处理:ACID特性与实战应用
本文深入解析了MySQL事务处理机制及ACID特性,通过银行转账、批量操作等实际案例展示了事务的应用技巧,并提供了性能优化方案。内容涵盖事务操作、一致性保障、并发控制、持久性机制、分布式事务及最佳实践,助力开发者构建高可靠数据库系统。
|
4月前
|
存储 关系型数据库 MySQL
介绍MySQL的InnoDB引擎特性
总结而言 , Inno DB 引搞 是 MySQL 中 高 性 能 , 高 可靠 的 存 储选项 , 宽泛 应用于要求强 复杂交易处理场景 。
202 15
|
4月前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
207 0
|
分布式计算 关系型数据库 MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
170 3
|
8月前
|
存储 关系型数据库 MySQL
【免费动手教程上线】阿里云RDS MySQL推出大容量高性能存储:高性能本地盘(最高16TB存储空间)、高性能云盘(最高64TB存储空间)
阿里云RDS MySQL提供高性能本地盘与高性能云盘等存储方案,满足用户大容量、低延迟需求。高性能本地盘单盘最大16TB,IO延时微秒级;高性能云盘兼容ESSD特性,支持IO性能突发、BPE及16K原子写等能力。此外,阿里云还提供免费动手体验教程,帮助用户直观感受云数据库 RDS 存储性能表现。
|
9月前
|
存储 关系型数据库 MySQL
利用Cron表达式实现MySQL数据库的定时备份
以上就是如何使用Cron表达式和mysqldump命令实现MySQL数据库的定时备份。这种方法的优点是简单易用,而且可以根据需要定制备份的时间和频率。但是,它也有一些限制,例如,它不能备份MySQL服务器的配置文件和用户账户信息,也不能实现增量备份。如果需要更复杂的备份策略,可能需要使用专门的备份工具或服务。
243 15
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
5258 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
10月前
|
SQL 关系型数据库 MySQL
MySQL:CTE 通用表达式
CTE(通用表表达式)为处理复杂查询提供了强大的工具。通过普通CTE,可以简化查询逻辑,提高可读性;通过递归CTE,可以优雅地处理层级结构数据。掌握CTE的使用,对于提升SQL查询能力和优化数据库操作有着重要意义。希望本文能帮助你更好地理解和使用MySQL中的CTE,提高工作效率和代码质量。
415 7
|
11月前
|
存储 关系型数据库 MySQL
MySQL进阶突击系列(09)数据磁盘存储模型 | 一行数据怎么存?
文中详细介绍了MySQL数据库中一行数据在磁盘上的存储机制,包括表空间、段、区、页和行的具体结构,以及如何设计和优化行数据存储以提高性能。

相关产品

  • 云数据库 RDS MySQL 版
  • 推荐镜像

    更多