[[419615]]
一 背景
在 MySQL 8.0 之前,Server 层和存储引擎(比如 InnoDB)会各自保留一份元数据(schema name, table definition 等),不仅在信息存储上有着重复冗余,而且可能存在两者之间存储的元数据不同步的现象。不同存储引擎之间(比如 InnoDB 和 MyISAM)有着不同的元数据存储形式和位置(.FRM, .PAR, .OPT, .TRN and .TRG files),造成了元数据无法统一管理。此外,将元数据存放在不支持事务的表和文件中,使得 DDL 变更不会是原子的,crash recovery 也会成为一个问题。
为了解决上述问题,MySQL 在 8.0 中引入了 data dictionary 来进行 Server 层和不同引擎间统一的元数据管理,这些元数据都存储在 InnoDB 引擎的表中,自然的支持原子性,且 Server 层和引擎层共享一份元数据,不再存在不同步的问题。
二 整体架构
典表的读写操作,包含开表(open table)、构造主键、主键查找等过程。client 和底层存储之间通过两级缓存来加速对元数据对象的内存访问,两级缓存都是基于 hash map 实现的,一层缓存是 local 的,由每个 client(每个线程对应一个 client)独享;二级缓存是 share 的,为所有线程共享的全局缓存。下面我将对 data dictionary 的数据结构和实现架构做重点介绍,也会分享一个支持原子的 DDL 在 data dictionary 层面的实现过程。
三 metadata 在内存和引擎层面的表示
data dictionary (简称DD)中的数据结构是完全按照多态、接口/实现的形式来组织的,接口通过纯虚类来实现(比如表示一个表的 Table),其实现类(Table_impl)为接口类的名字加 _impl 后缀。下面以 Table_impl 为例介绍一个表的元数据对象在 DD cache 中的表示。
1 Table_impl
Table_impl 类中包含一个表相关的元数据属性定义,比如下列最基本引擎类型、comment、分区类型、分区表达式等。
- class Table_impl : public Abstract_table_impl, virtual public Table { // Fields. Object_id m_se_private_id; String_type m_engine; String_type m_comment; // - Partitioning related fields. enum_partition_type m_partition_type; String_type m_partition_expression; String_type m_partition_expression_utf8; enum_default_partitioning m_default_partitioning; // References to tightly-coupled objects. Index_collection m_indexes; Foreign_key_collection m_foreign_keys; Foreign_key_parent_collection m_foreign_key_parents; Partition_collection m_partitions; Partition_leaf_vector m_leaf_partitions; Trigger_collection m_triggers; Check_constraint_collection m_check_constraints;};
Table_impl 也是代码实现中 client 最常访问的内存结构,开发者想要增加新的属性,直接在这个类中添加和初始化即可,但是仅仅如此不会自动将该属性持久化到存储引擎中。除了上述简单属性之外,还包括与一个表相关的复杂属性,比如列信息、索引信息、分区信息等,这些复杂属性都是存在其他的 DD 表中,在内存 cache 中也都会集成到 Table_impl 对象里。
从 Abstract_table_impl 继承来的 Collection m_columns 就表示表的所有列集合,集合中的每一个对象 Column_impl 表示该列的元信息,包括数值类型、是否为 NULL、是否自增、默认值等。同时也包含指向 Abstract_table_impl 的指针,将该列与其对应的表联系起来。
- class Column_impl : public Entity_object_impl, public Column { // Fields. enum_column_types m_type; bool m_is_nullable; bool m_is_zerofill; bool m_is_unsigned; bool m_is_auto_increment; bool m_is_virtual; bool m_default_value_null; String_type m_default_value; // References to tightly-coupled objects. Abstract_table_impl *m_table;};
此外 Table_impl 中也包含所有分区的元信息集合 Collection m_partitions,存放每个分区的 id、引擎、选项、范围值、父子分区等。
- class Partition_impl : public Entity_object_impl, public Partition { // Fields. Object_id m_parent_partition_id; uint m_number; Object_id m_se_private_id; String_type m_description_utf8; String_type m_engine; String_type m_comment; Properties_impl m_options; Properties_impl m_se_private_data; // References to tightly-coupled objects. Table_impl *m_table; const Partition *m_parent; Partition_values m_values; Partition_indexes m_indexes; Table::Partition_collection m_sub_partitions;};
因此获取到一个表的 Table_impl,我们就可以获取到与这个表相关联的所有元信息。
2 Table_impl 是如何持久化存储和访问的
DD cache 中的元信息都是在 DD tables 中读取和存储的,每个表存放一类元信息的基本属性字段,比如 tables、columns、indexes等,他们之间通过主外键关联连接起来,组成 Table_impl 的全部元信息。DD tables 存放在 mysql 的表空间中,在 release 版本对用户隐藏,只能通过 INFORMATION SCHEMA 的部分视图查看;在 debug 版本可通过设置 SET debug='+d,skip_dd_table_access_check' 直接访问查看。比如:
- root@localhost:test 8.0.18-debug> SHOW CREATE TABLE mysql.tables\G
(责任编辑:知识)
我国交通运输固定资产投资 今年将超3.2万亿元 加快补齐短板
山东威海市出台居家和社区养老服务项目新方案 推动试点工作顺利开展
人社部:2019年三项社会保险基金总收入5.82万亿元 运行平稳
中盈盛达融资担保(01543.HK)完成发行2.60亿元公司债 票面利率为4.60%