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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核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

参考文档:

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
存储 关系型数据库 MySQL
Linux 安装 mysql 及配置存储位置
Linux 安装 mysql 及配置存储位置
103 3
|
2月前
|
存储 关系型数据库 MySQL
MySQL——数据库备份上传到阿里云OSS存储
MySQL——数据库备份上传到阿里云OSS存储
92 0
|
2月前
|
存储 关系型数据库 MySQL
mysql 使用变量存储中间结果的写法
mysql 使用变量存储中间结果的写法
|
11天前
|
JSON 关系型数据库 MySQL
MySQL 8.0 新特性
MySQL 8.0 新特性
62 10
MySQL 8.0 新特性
|
21天前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
5天前
|
存储 关系型数据库 MySQL
深入解析MySQL数据存储机制:从表结构到物理存储
深入解析MySQL数据存储机制:从表结构到物理存储
14 1
|
2月前
|
算法 关系型数据库 MySQL
一天五道Java面试题----第七天(mysql索引结构,各自的优劣--------->事务的基本特性和隔离级别)
这篇文章是关于MySQL的面试题总结,包括索引结构的优劣、索引设计原则、MySQL锁的类型、执行计划的解读以及事务的基本特性和隔离级别。
|
2月前
|
SQL 算法 关系型数据库
(二十)MySQL特性篇:2022年的我们,必须要懂的那些数据库新技术!
 MySQL数据库从1995年诞生至今,已经过去了二十多个年头了,到2022.04.26日为止,MySQL8.0.29正式发行了GA版本,在此之前版本也发生了多次迭代,发行了大大小小N多个版本,其中每个版本中都有各自的新特性,所有版本的特性加起来,用一本书的篇幅也无法完全阐述清楚,因此本章主要会挑重点特性来讲,具体各版本的特性可参考MySQL官网的开发手册。
|
3月前
|
关系型数据库 MySQL 存储
|
2月前
|
存储 小程序 关系型数据库
原生小程序 获取手机号并进行存储到mysql数据库
原生小程序 获取手机号并进行存储到mysql数据库

相关产品

  • 云数据库 RDS MySQL 版
  • 下一篇
    无影云桌面