范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

MySQL8。0数据字典表

  MySQL 8.0 对数据字典进行了重构,用户表、数据字典表、MySQL 其它系统表的元数据都 统一  保存到 mysql 库  的数据字典表中了。
  mysql 库中,除了  general_log  、slow_log   2 个日志表,其它所有表的存储引擎都是 InnoDB  ,伴随而来的是 DDL 终于能够支持原子操作了。
  以  DROP TABLE t1, t2   为例,不会出现 t1 表删除成功,t2 表删除失败的情况,而是要么都删除成功,要么都删除失败。
  本文我们就来聊聊 MySQL 8.0 中的数据字典表。
  本文内容基于 MySQL 8.0.29 源码。
  目录 1. 概述 2. 数据字典表有哪些? 3. 数据字典表元数据在哪里? 4. 创建数据字典表 5. 打开数据字典表 6. 总结
  正文 1. 概述
  MySQL 8.0 重构数据字典之后,废除了 MySQL 5.7 中用于保存元数据的磁盘文件: .frm  、.par  、.TRN  、.TRG  、.isl  、db.opt  、ddl_log.log  。
  如果想要了解上面这些磁盘文件都保存了什么元数据,可以参照 MySQL 官方文档: https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-file-removal.html
  这些文件被废除之后,原本保存到这些文件中的元数据,都保存到数据字典表中了。
  数据字典表本身也大变样了: 数据字典表不再位于 InnoDB 系统表空间,而是迁移到 mysql 库中,mysql 库位于 mysql 表空间,磁盘文件为  mysql.ibd  。SYS_TABLES、SYS_COLUMNS、SYS_INDEXES、SYS_FIELDS 这 4 个数据字典表也不再完全依赖硬编码在源码中的元数据了,而是和其它表一样,使用保存在 mysql 库的数据字典表中的元数据。
  上面 4 个数据字典表的名字也发生了变化,后面会介绍。 2. 数据字典表有哪些?
  按照官方文档的定义,MySQL 8.0 一共有 31 张数据字典表: dd_properties innodb_ddl_log catalogs character_sets check_constraints collations column_statistics column_type_elements columns events foreign_key_column_usage foreign_keys index_column_usage index_partitions index_stats indexes parameter_type_elements parameters resource_groups routines schemata st_spatial_reference_systems table_partition_values table_partitions table_stats tables tablespace_files tablespaces triggers view_routine_usage view_table_usage
  上面只是简单列出了数据字典表的表名,如果想了解每个表存放了什么内容,可以参照官方文档: https://dev.mysql.com/doc/refman/8.0/en/system-schema.html
  默认情况下,我们是看不到数据字典表的,需要满足以下条件才能看到: 源码编译 Debug 版本 MySQL,以使用 cmake 编译为例,需要带上  -DCMAKE_BUILD_TYPE=Debug   编译选项。连接 MySQL 之后,先执行下面的 SQL 告诉 MySQL 跳过数据字典表的权限检查: SET SESSION debug = "+d,skip_dd_table_access_check"
  满足以上 2 个条件之后,执行下面这条 SQL 就可以看到所有数据字典表了: SELECT a.name AS db_name, b.* FROM mysql.schemata AS a INNER JOIN mysql.tables AS b ON a.id = b.schema_id WHERE b.schema_id = 1 AND b.hidden = "System" ORDER BY b.id
  执行上面的 SQL 列出来的表有 32 个,其中  innodb_dynamic_metadata   表不属于数据字典表。
  上面列出的数据字典表中,有 4 个需要重点介绍,因为不管是数据字典表本身,还是用户表,都离不开这 4 个表: tables  :存储表的元数据,包括表空间 ID、数据库 ID、表 ID、表名、表注释、行格式等信息,对应 MySQL 5.7 中的数据字典表 SYS_TABLES  。columns  :存储表中字段的元数据,包括表 ID、字段 ID、字段名、字段注释、字段类型、是否自增等信息,对应 MySQL 5.7 中的数据字典表 SYS_COLUMNS  。indexes  :存储表的索引元数据,包括表空间 ID、表 ID、索引 ID、索引名、索引注释、是否是隐藏索引等信息,对应 MySQL 5.7 中的数据字典表 SYS_INDEXES  。index_column_usage  :存储索引中字段的元数据,包括索引 ID、字段 ID、字段在索引中的编号(从 1 开始)、索引字段长度(如果是前缀索引字段,则是前缀的长度)、索引字段排序、是否隐藏,共 6   个字段,对应 MySQL 5.7 中的数据字典表 SYS_FIELDS  。
  这个表中没有包含更详细的字段信息,如果需要,可以通过字段 ID 到 columns   表获取。
  index_column_usage 和 SYS_FIELDS 表不完全一样,有 2 点需要说明: index_column_usage 包含 6 个字段,比 SYS_FIELDS 多 3 个字段:
  order  :表示索引字段的排序。
  length  :hidden = 0   时,表示索引字段长度,或前缀索引字段的前缀长度;hidden = 1   时,字段值为 NULL  。
  hidden  :0   表示索引中该字段由用户定义;1   表示索引中该字段是 MySQL 给加上的。以下是一个测试表,图中  name   是从 columns 表中连表查询得到的,其它都是 index_column_usage 表的字段。CREATE TABLE `t5` (    `id` int unsigned NOT NULL AUTO_INCREMENT,    `str1` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL DEFAULT "",    `i1` int NOT NULL DEFAULT "0",    `str2` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL DEFAULT "",    `i2` int NOT NULL DEFAULT "0",    PRIMARY KEY (`id`) USING BTREE,    UNIQUE KEY `idx_i1` (`i1`) USING BTREE,    KEY `idx_str1` (`str1`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
  index_id = 310   是主键索引,hidden = 0   的记录是主键字段;hidden = 1   的记录是主键索引中的其它字段,也就是表中的字段。
  index_id = 312   是二级索引,其中 str1 是前缀索引字段,前缀长度为 255 * 3(utf8 一个字符最多占用的字节数) = 765,hidden = 0   表示 str1 是用户定义的二级索引字段;hidden = 1   的记录是 MySQL 自己增加到二级索引中的主键字段。index_column_usage 表中的  ordinal_position   表示编号,从 1 开始;SYS_FIELDS 中的 POS   表示序号,从 0 开始。
  除了在 Debug 版本的 MySQL 中设置跳过数据字典表的权限检查之外,还可以通过  information_schema   数据库中的表或视图查看其对应的数据字典表:
  数据字典表information_schema 表或视图  tablesINNODB_TABLES columnsINNODB_COLUMNS  indexesINNODB_INDEXES index_column_usage
  INNODB_FIELDS  …………
  3. 数据字典表元数据在哪里?
  数据字典表用于存储用户表的元数据,这个比较好理解,因为创建用户表的时候,所有数据字典表都已经存在了,把用户表的各种元数据插入到相应的数据字典表就可以了。
  数据字典表本身的元数据也会保存到数据字典表里,但是某个数据字典表创建的时候,有一些数据字典表还没有创建,这就有问题了。
  我们以  columns  、indexes   这 2 个数据字典表为例来说明:columns 表先于 indexes 表创建,columns 表创建成功之后,需要把索引元数据保存到 indexes 表中,而此时 indexes 表还没有创建,columns 表的索引元数据自然也就没办法保存到 indexes 表中了。
  MySQL 解决这个问题的方案是引入一个中间层,用于 临时存放  所有数据字典表的各种元数据,等到所有数据字典表都创建完成之后,再把临时存放在中间层的所有数据字典表的元数据保存到相应的数据字典表中。
  这里所谓的中间层实际上是一个 存储适配器  ,源码中对应的类名为 Storage_adapter  ,这是一个实现了单例模式的类。
  MySQL 在初始化数据目录的过程中, Storage_adapter   类的实例属性 m_core_registry   就是所有数据字典表元数据的临时存放场所。4. 创建数据字典表
  我们安装 MySQL 完成之后,想让 MySQL 运行起来,要做的第一件事就是初始化 MySQL,实际上就是初始化 MySQL 数据目录。
  初始化过程会创建 MySQL 运行时需要的各种表空间、数据库、表,其中就包含数据字典表。
  创建数据字典表的过程分为 3 个步骤进行:
  第 1 步  ,把代表每个数据字典表的 Object_table   对象注册到 System_tables 类的实例属性 m_registry   中。
  除了数据字典表,m_registry 中还包含了  mysql 库  中的其它 MySQL 系统表。
  第 2 步  ,循环 m_registry 中的所有表,通过 Object_table 得到数据字典表的 DDL,然后调用 dd::execute_query()   执行 DDL 语句创建数据字典表。
  dd::execute_query() 创建数据字典表的过程中,会把表的元数据 临时存放  到 Storage_adapter   类的实例属性 m_core_registry   中,而不会保存到各种元数据对应的数据字典表中,这么做的原因在上一小节中介绍数据字典表的元数据在哪里  时,已经介绍过了,这里不再赘述。
  dd::execute_query() 执行完一个数据字典表的 DDL 语句之后,这个数据字典表在表空间中就已经存在了,m_registry 中的所有表都处理完成之后,所有数据字典表就都存在了。
  第 3 步  ,循环 m_registry 中的所有表,把每个表本身的元数据(数据库 ID、表 ID、表名、注释、字段数量等)保存到 mysql.tables   数据字典表中,然后把表的字段、索引等元数据保存到对应的数据字典表中。
  所有数据字典表的元数据都从  Storage_adapter   类的实例属性 m_core_registry   中读取。
  经过 3 个步骤的通力协作,所有数据字典表的元数据就都保存到数据字典表中了,这个鸡生蛋、蛋生鸡的问题,就这样通过引入外力( m_core_registry  )解决了。5. 打开数据字典表
  数据字典表保存着 MySQL 运行过程中需要的一系列关键数据,使用频次很高,MySQL 启动过程中就会把数据字典表的 元数据  都加载到内存中,这就是打开表  的过程。
  也就是说, 打开数据字典表  是在 MySQL 启动过程中完成的。
  前面我们介绍过,数据字典表的元数据也是保存在数据字典表中的。
  MySQL 启动过程中,要先打开数据字典表才能拿到数据字典表的元数据,而要拿到数据字典表的元数据,又必须先打开数据字典表。
  这个过程很绕,不是很好理解,我们来打个比方:数据字典表是一个房间,数据字典表的元数据是打开房间门的钥匙。
  现在问题来了,因为 MySQL 把数据字典表的元数据保存在数据字典表中,这就相当于把打开房间门的钥匙落在房间里了。
  要想打开房间,必须先拿到钥匙,而要想拿到钥匙又必须先打开房间,这样一转换,问题是不是更好理解点了?
  我们先来想想怎么解决房间和钥匙问题,如果把打开房间的钥匙落在房间里了,有哪些办法可以解决?
  我能想到的有以下 3 种解决方案: 暴力破解,把锁撬开。 找专业的开锁师傅把锁打开。 用备用钥匙开门。这个方法最好,但是有个 前提条件  :已经提前准备好了备用钥匙。
  MySQL 里没有前 2 种方案,而是留了一把备用钥匙,也就是第 3 种方案,接下来我们看看 MySQL 打开数据字典表的过程:
  第 1 步  ,和创建数据字典表  一样,把代表每个数据字典表的 Object_table 对象注册到 System_tables   类的实例属性 m_registry   中。
  每个数据字典表的 Object_table 对象中,都定义了这个表的表名、字段、索引、外键等信息。
  Object_table 对象中保存的并不是 DDL 语句,却类似于我们建表时的 DDL 语句。
  下面这个例子是源码中 表空间  数据字典表 mysql.tablespaces   Object_table 对象中定义的该表的信息:Tablespaces::Tablespaces() {   // 表名   m_target_def.set_table_name("tablespaces");    // 字段   m_target_def.add_field(FIELD_ID, "FIELD_ID", "id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT");   m_target_def.add_field(FIELD_NAME, "FIELD_NAME", "name VARCHAR(268) NOT NULL COLLATE " + String_type(Object_table_definition_impl::name_collation()->m_coll_name));   m_target_def.add_field(FIELD_OPTIONS, "FIELD_OPTIONS", "options MEDIUMTEXT");   m_target_def.add_field(FIELD_SE_PRIVATE_DATA, "FIELD_SE_PRIVATE_DATA", "se_private_data MEDIUMTEXT");   m_target_def.add_field(FIELD_COMMENT, "FIELD_COMMENT", "comment VARCHAR(2048) NOT NULL");   m_target_def.add_field(FIELD_ENGINE, "FIELD_ENGINE", "engine VARCHAR(64) NOT NULL COLLATE utf8_general_ci");   m_target_def.add_field(FIELD_ENGINE_ATTRIBUTE, "FIELD_ENGINE_ATTRIBUTE", "engine_attribute JSON");    // 索引   m_target_def.add_index(INDEX_PK_ID, "INDEX_PK_ID", "PRIMARY KEY(id)");   m_target_def.add_index(INDEX_UK_NAME, "INDEX_UK_NAME", "UNIQUE KEY(name)");      // 如果有外键等其它信息,也会加在这里 }
  第 2 步  ,循环 m_registry 中的所有表,通过 Object_table 得到数据字典表的 DDL,然后调用 dd::execute_query()   执行 DDL 语句创建数据字典表。
  和 创建数据字典表  中的第 2 步不一样,dd::execute_query() 执行 DDL,并不会真正的创建表 ,只是为了生成数据字典表元数据,并把元数据保存到 Storage_adapter   类的实例属性 m_core_registry   中。
  保存到 m_core_registry 中的数据字典表元数据,就是我们前面说的 备用钥匙  ,有了这把备用钥匙,就能打开数据字典表了。
  第 3 步  ,循环 m_registry 中的所有表,通过第 2 步生成的数据字典表元数据,去 mysql 表空间中(表空间文件:mysql.ibd  )读取各个数据字典表的元数据。
  这一步执行完成之后,所有数据字典表的元数据都被加载到内存中了,数据字典表都被打开了。
  第 4 步  ,循环 m_registry 中的所有表,把数据字典表的元数据从 m_core_registry 删除。
  第 5 步  ,循环 m_registry 中所有的表,把从表空间中读取出来的数据字典表的元数据存入 m_core_registry 中。
  不过,这一步存入 m_core_registry 的并不是所有数据字典表的元数据,而是 22 个核心( CORE  )数据字典表的元数据:catalogs character_sets check_constraints collations column_statistics column_type_elements columns foreign_key_column_usage foreign_keys index_column_usage index_partitions indexes resource_groups schemata table_partition_values table_partitions tables tablespace_files tablespaces triggers view_routine_usage view_table_usage
  1 ~ 5 步执行完成之后,m_core_registry 中就只包含上面 22 个核心数据字典表的元数据了,有了这些表的元数据,就可以打开其它所有表了。
  第 6 步  ,调用 dd::execute_query()   执行 FLUSH TABLES   关闭已经打开的所有数据字典表、非数据字典表,后续就可以用从数据字典表中读取出来的元数据来打开数据字典表和其它所有需要的表了。
  到这里,打开数据字典表的大体流程就已经介绍完了, 也许大家会有疑问 :
  第 2 步调用  dd::execute_query()   执行 DDL,已经拿到了数据字典表的元数据。
  为了区分,把这里拿到的元数据叫作 备用元数据  。
  第 3 步根据 备用元数据  打开数据字典表,从表空间中读取到数据字典表的元数据。
  同样为了区分,把这里拿到的元数据叫作 原配元数据  。
  第 4 步从  m_core_registry   中删除备用元数据  。第 5 步把原配元数据  存入 m_core_registry  。
  数据字典表的备用元数据和原配元数据不是一样的吗?为什么还要用原配元数据替换备用元数据,这是不是多此一举?
  我没有逐个对比备用元数据和原配元数据是否完全一样,这是个不小的工程。不过,既然源码中这么实现,那应该是有它的原因,只是我还没有发现。如果后面发现其中的原因,我会再补充到我的博客中。 6. 总结
  要理解 MySQL 8.0 中的数据字典表,核心是理解以下 2 点: 初始化数据目录时,数据字典表的元数据是怎么存放到数据字典表中的?
  这主要是借助了 Storage_adapter 类实例的 m_core_registry 属性。
  在创建数据字典表的过程中,先创建每个数据字典表,并把元数据临时存放到 m_core_registry   中,所有数据字典表都创建成功之后,最后再一次性把所有数据字典表的元数据保存到对应的数据字典表中。MySQL 启动时,怎么用数据字典表的元数据打开数据字典表?
  这同时借助了硬编码在源码中的数据字典表定义,以及 Storage_adapter 类实例的 m_core_registry   属性。
  MySQL 启动过程中,先通过 Object_table 得到创建数据字典表的 DDL,调用 dd::execute_query()   执行 DDL,拿到元数据(备用原数据  ),把备用元数据临时存放  到 m_core_registry 属性中,再通过备用元数据打开数据字典表。

Steam十大高画质游戏,方舟生存进化泰克手雷比牛皮糖还难甩武器研发,这在军事上是一个很热门的话题,毕竟现在各大国之间都比较忌惮,是不可能乱丢核武器的,这个时候哪个国家能够率先研发出新的武器,哪个国家就能在常规战争中获取更大的优势。在Ste卧龙苍天陨落新情报人形敌人光荣发布了卧龙苍天陨落新情报人形敌人。人型敌人也不容小觑!下图中化为妖魔的黄巾士兵手持两柄大刀挥舞如飞,一身怪力威不可当。若掉以轻心将付出惨痛代价。下图为形似人鱼的妖魔水鬼。水鬼通年纪大了喝白酒要注意啥?行家牢记1喝3不碰,早懂益处多年纪大了就得戒酒了,喝酒对身体不好相信每一位喝酒的人都对这些话熟悉得很。或许是来自家人的关心,也或许是来自朋友的忠告。在大众的潜意识里,喝酒就是有害身体健康的,就是对身体不好的,所胃热的饮食调理胃热症状口臭食欲不振胃胀疼厌食恶心打嗝嗳气口干口苦等。胃热可能是患者本身消化功能欠佳营养不良,当食用了过多辛辣刺激冷饮油腻甜食物,出现食物积滞在胃内难以消化,导致胃火旺盛,出现胃热比油和盐更伤身!中老年人要少吃这3种物质,可护心血管健康经临床研究发现,大多数患有心脑血管相关疾病的人,在饮食方面都存在问题,尤其是经常食用富含油脂的食物,这种类型的食物当中大多含有比较高的胆固醇和脂肪酸。脂肪酸既人体所必需的营养物质,就剩詹姆斯浓眉了,才两年啊!湖人冠军阵容彻底散了2020年洛杉矶湖人队拿到了NBA总冠军,这让他们的总冠军数追评了波士顿凯尔特人,成为了NBA历史上总冠军最多的球队之一。这也是湖人时隔10年之后又一次拿到总冠军,然而好景不长,湖云顶之弈12。14环境大变,强势上分阵容推荐,这几套优选兄弟们好我是摩昂解说,12。14版本来了,由于摩昂在外服测试了整整一天,今天的弈图排行就先更新,时间不够了,还有一些阵容没有测试到,明天或者后天给大家在出排行榜。下面摩昂就把自己对12。14最强偷分阵容幽影蜘蛛,大成可灭龙大家好我是北派。今天物理阵容又又又削弱了,赌一费卡阵容彻底烂掉,法系阵容过渡更顺利,八人口抽到一张敖兴索尔就能锁血。我们也别想着什么阵容能打大成龙王敖兴了,这不现实,而是需要考虑什国安未来主力阵容或进行调整,四个位置迎强援助阵,于大宝成核心北京国安在本轮中超跟上海申花狭路相逢,这场比赛对于球队来说并不好踢。因为,申花已经遭遇了多轮比赛不胜,急需一场胜利。国安面对困兽犹斗的申花,确实需要打起精神。国安主帅隋东亮原本的战适合发朋友圈的快乐句子1笑是一种没有副作用的镇静剂。2于千万人之中遇见你所遇见的人,于千万年之中时间的无涯的荒野里,没有早一步,也没有晚一步,刚巧赶上了。3躺在家里的床上看看剧琢磨一些美食看看书,美好的痛疼是最好的老师自己醒悟,那叫悟道。别人告诉,那叫知道。醒悟,在意识上由模糊转向清醒,由错误转向正确。最大的醒悟,就是看到自己的问题,懂得看自己的问题,而不是责怪别人,有一位圣人说过,从别人的过错
斗破苍穹萧玄时代萧族也未必是远古八族之首萧炎的出身还是不错的,当年的萧家可是远古八族之一的强横势力,在整个斗气大陆上只有这些远古种族才算是至强的势力,和他们比起来一些大宗派则是有些逊色了,不过萧炎登场的时候萧族早就没落上河北省的区划变动,11个地级市之一,唐山市为何有14个区县?在之前的文章中,作者和大家聊了一系列关于我国河北省各个地级市区划变动的故事,例如石家庄市邯郸市等等。今天,我们聊聊河北省唐山市。唐山市是河北省11个地级市之一,同时,也是河北省经济河南第一懒人杨锁脚不沾地吃饭靠喂,23岁懒死家中,到底有多懒1hr2009年春节,河南罗山朱堂乡的村民都在张灯结彩迎接新年。每家每户都喜气洋洋的,只有杨家不是。杨家最后的独苗杨锁死在了寒冷的冬夜里。杨锁曾经在村中非常出名,村里人都说他是少见女性什么时候绝经比较好?绝经越迟,越容易长寿吗?很多人想错了绝经晚的人,更长寿!别得瑟了,我听说啊,这绝经晚的人容易得癌症!今年已经58岁的苏女士,到现在还一直没有绝经,她觉得,绝经就意味着衰老,所以自己没绝经,就会比别人老的慢一些,对于这520成年人的浪漫,是用钱堆起来的在网上看到一个段子男生为了躲避520节日,在519跟女友提分手,打算等节日热度过去后,再求女友复合。真是个小机灵鬼。不得不说,这届年轻人太难了单身的年轻人,更难。只想安安静静谈个恋南开教授被女学生举报作风不端,一教师被解聘,女生行为也有目的南开教授被女学生举报作风不端,一教师被解聘,女生的行为也有目的都说老师和护士是世上最伟大的工作。而那些受过良好教育的老师,更是普通人望尘莫及,能在大学里当老师的,都是有一定学识的,蔡英文上台6年,民众怒斥十缺十乱民进党当局领导人蔡英文上台6年,多项重要政策违背民意。图为台湾民众举行集会反对台当局强行进口美国瘦肉精猪肉。(资料图片)5月20日是民进党当局领导人蔡英文上台执政6周年。虽然民进党柠檬能杀死12种癌,比化疗强一万倍?喝柠檬水能抗癌吗?真相来了柠檬比化疗强一万倍!最近张阿姨在手机上看到一篇文章,让她大为惊喜。张阿姨得了肺癌,已经做了手术,还在化疗,看了文章后,十分想把化疗停了。文章里指出柠檬提取物可以杀死肺癌结直肠癌胰腺卖炭翁改装的法拉利SF901100匹尾翼更惊艳在卖炭翁Mansory所改装的车型中,法拉利的出镜率还是很高的,前不久法拉利Roma就被Mansory重点照顾,开发了一套非常惊艳的作品。而今天Mansory继续对法拉利旗下SF9核酸检测,既要便民可及,也要暖心服务您今天做核酸了吗?请问附近哪儿做核酸方便?这个采样点开到几点?上述这些已成为许多老百姓日常对话的一部分。一切都是为了应对仍复杂严峻的疫情形势。国家卫生健康委党组书记主任马晓伟近日表45岁陈数到小区做核酸被拍,一脸素颜细腿抢镜,骑单车回家接地气5月19日,45岁知名女星陈数到小区做核酸,正好被狗仔拍到美照,让我们一睹女神私下的近况。照片中的陈数身穿灰色卫衣,戴着棒球帽,脸上连妆都没有化,造型打扮十分低调。陈数的身边还跟着