当前位置: 首页 > 游戏攻略 > MySQL 8.0数据字典的初始化与启动加载

MySQL 8.0数据字典的初始化与启动加载

来源:网络 作者:趣玩小编 发布时间:2024-06-24 16:14:02

本文分享自华为云社区《MySQL全文索引源码剖析之insert语句执行过程》,作者:GaussDB 数据库。

本文主要介绍MySQL 8.0数据字典的基本概念和数据字典的初始化与启动加载的主要流程。

数据字典(Data Dictionary, DD)用来存储数据库内部对象的信息,这些信息也被称为元数据(Metadata),包括schema名称、表结构、存储过程的定义等。

图1 MySQL 8.0之前的数据字典

图片来源:MySQL 8.0 Data Dictionary: Background and Motivation

如图1所示,MySQL 8.0之前的元数据,分散存储在许多不同的位置,包括各种元数据文件,不支持事务的表和存储引擎特有的数据字典等;Server层和存储引擎层有各自的数据字典,其中一部分是重复的。

以上的设计导致支持原子的DDL变得很困难,因此MySQL 8.0之前,如果DDL过程中发生crash,后期的恢复很容易出现各种问题,导致表无法访问、复制异常等。

如图2所示,MySQL 8.0使用支持事务的InnoDB存储引擎作来存储元数据,实现数据字典的统一管理。这个改进消除了元数据存储的冗余,通过支持原子DDL,实现了DDL的crash safe。

图2 MySQL 8.0数据字典

图片来源:MySQL 8.0: Data Dictionary Architecture and Design

数据字典表都是隐藏的,只有在debug编译模式下,可以通过设置开关set debug='+d,skip_dd_table_access_check'来直接查看数据字典表。

上面查询得到的表就是隐藏的数据字典表,MySQL的元数据存储在这些表中。

在release编译模式下,如果要查看数据字典信息,只能通过INFORMATION_SCHEMA中的视图来查询。例如,可以通过视图information_schema.tables查询数据字典表mysql.tables。

数据字典的代码位于sql/dd目录,所有数据字典相关的信息都在dd这个命名空间中,各数据字典表本身的定义位于sql/dd/impl/tables目录的代码中,可以理解为数据字典表的元数据在代码中已经定义好了。

以存储schema信息的schemata表为例,其类的声明如下:

其构造函数定义了该表的名称、各字段、索引和外键等信息,以及该表默认存储的数据信息,如下所示:

在初始化和启动时,会使用Object_table_definition_impl::get_ddl()函数来获取m_target_def中信息所生成的DDL语句,创建出schemata表;使用Object_table_definition_impl::get_dml()获取DML语句,用于初始化表中的数据。

dd::tables::Schemata类的继承关系,如图3。所有的数据字典表对应的类,最终都是派生自dd::Object_table,便于统一处理。

图3 dd::tables::Schemata类

对于这些表中存储的元数据所对应的对象,或者说这些表中的每一行数据所对应的一个对象,比如一个schema、table、column等,代码中也有对应的类。

还是以schema为例,它对应的类是dd::Schema,实现类是dd::Schema_impl,代表的是schema这种数据库内部对象,也是mysql.schemata表中的一行。

所有数据字典中所存储的对象在代码中的基类都是dd::Weak_object,如图4:

图4 dd::Schema_impl类

schema的id和name在dd::Entity_object_impl中,其他字段在实现类dd::Schema_impl中。

实现类dd::Schema_impl主要实现了对于元数据对象的各属性的读写访问,与从数据字典中的元数据表schemata的行记录中,存取元数据的接口。

主要相关接口如下:

dd::Schema_impl主要实现了store_attributes和restore_attributes接口,依据dd::tables::Schemata中的表定义信息,读取或存储schema的各个属性信息。

依据以上介绍的,数据字典表的类与数据库内部对象的类,结合InnoDB存储引擎的接口,实现了对于存储于数据字典各个表中的元数据的读写访问。

例如,存储新建的database的元数据到schema内存对象中:

持久化到对应的InnoDB表mysql.schemata中:

初始化MySQL数据库实例时,即执行mysqld -initialize时,main函数会启动一个bootstrap线程来进行数据字典的初始化,并等待其完成。

数据字典的初始化函数入口是dd::bootstrap::initialize,主要流程如下:

图5 数据字典初始化流程

其中,DDSE指的是Data Dictionary Storage Engine,数据字典的存储引擎,即InnoDB。DDSE初始化过程主要是对InnoDB进行必要的初始化,并获取DDSE代码中预先定义好的表的定义与表空间的定义。

InnoDB预定义的数据字典表:

InnoDB预定义的系统表空间:

InnoDB的ddse_dict_init接口的实现为innobase_ddse_dict_init,会先调用innobase_init_files初始化所需文件并启动InnoDB。

主要代码流程如下:

在DDSE初始化并启动的基础上,就可以进行剩下的数据字典初始化过程,主要就是创建数据字典的schema和表。这些表的元数据在执行flush_meta_data时进行持久化。

值得注意的是表mysql.dd_properties,它会存储版本信息等数据字典的属性,还会存储其他数据字典表的定义、id、se_private_data等信息,在数据库启动时使用。

数据字典初始化整体执行的函数调用总结,如图6:

图6 数据字典初始化的函数调用

数据字典的启动过程所执行的函数与初始化时十分相似,大部分在函数内部通过opt_initialize全局变量来区分初始化和启动,执行不同的代码逻辑。

与初始化的主要区别是元数据不再需要生成并持久化到存储,而是从存储读取已有的元数据。InnoDB文件是打开已有的,而不是新建。

数据字典启动的入口是dd::upgrade_57::do_pre_checks_and_initialize_dd。这里虽然有'upgrade_57'这种名称的namespace,但是正常的启动也是从这里开始。

与初始化相同,数据字典的启动也是先准备好DDSE,即启动InnoDB,然后再进行后面启动数据字典的步骤。打开数据字典之前,InnoDB会进行数据字典的恢复,确保重启前的DDL都正常的提交或回滚,数据字典元数据和数据是处于一致的状态。

dd::upgrade_57::restart_dictionary调用dd::bootstrap::restart,后面的启动步骤由它来实现,主要过程如下。

注意这里的创建表,是创建内存中的对象,不是物理上新创建一个表。这些表的元数据都已经在初始化时持久化了。

启动时各个数据字典表的根页面信息是从 mysql.dd_properties表中获取的,通过该页面可以访问对应表的所有数据。

mysql.dd_properties表的根页面是固定的,并且它里面保存了数组字典表本身的元数据。相关函数:dd::get_se_private_data()。

MySQL 8.0新设计实现的数据字典,解决了之前版本的数据字典冗余,DDL原子性、crash safe等问题。通过对数据字典的初始化流程,以及数据字典正常重启时加载流程的梳理,希望读者对新数据字典的实现和运行有一个更深入的了解。

后续会继续探究MySQL 8.0数据字典版本升级的内容,敬请期待。

更多技术专栏内容: https://bbs.huaweicloud.com/blogs/427078

点击关注,第一时间了解华为云新鲜技术~

热门推荐 更多 +
休闲益智 | 945.71MB
我的世界是一款风靡全球的3D第一人称沙盒...
9.6
角色扮演 | 878.96MB
最新版《汉家江湖》是一款以武侠为题材、以...
9.5
飞行射击 | 262.79MB
《荒野乱斗》是快节奏射击类多人对战游戏。...
9.5
飞行射击 | 102.9M
掌上飞车手游app是由腾讯特别为QQ飞车...
9.2
休闲益智 | 263.56MB
开心消消乐是一款轻松休闲的手游,也是一款...
9.6