当前位置:首页 >综合 >MySQL 深潜 造成了元数据无法统一管理

MySQL 深潜 造成了元数据无法统一管理

2024-06-29 06:21:01 [百科] 来源:避面尹邢网

MySQL 深潜 - 一文详解 MySQL Data Dictionary

作者:泊歌 数据库 MySQL 在 MySQL 8.0 之前,Server 层和存储引擎(比如 InnoDB)会各自保留一份元数据(schema name, table definition 等),不仅在信息存储上有着重复冗余,而且可能存在两者之间存储的元数据不同步的现象。

 [[419615]]

一 背景

MySQL 深潜 造成了元数据无法统一管理

在 MySQL 8.0 之前,Server 层和存储引擎(比如 InnoDB)会各自保留一份元数据(schema name, table definition 等),不仅在信息存储上有着重复冗余,而且可能存在两者之间存储的元数据不同步的现象。不同存储引擎之间(比如 InnoDB 和 MyISAM)有着不同的元数据存储形式和位置(.FRM, .PAR, .OPT, .TRN and .TRG files),造成了元数据无法统一管理。此外,将元数据存放在不支持事务的表和文件中,使得 DDL 变更不会是原子的,crash recovery 也会成为一个问题。

MySQL 深潜 造成了元数据无法统一管理

MySQL 深潜 造成了元数据无法统一管理

为了解决上述问题,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、分区类型、分区表达式等。

  1. 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 的指针,将该列与其对应的表联系起来。

  1. 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、引擎、选项、范围值、父子分区等。

  1. 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' 直接访问查看。比如:

  1. root@localhost:test 8.0.18-debug> SHOW CREATE TABLE mysql.tables\G

    (责任编辑:知识)

    推荐文章
    热点阅读