MySQL8.0: Serialized Dictionary Information(SDI) 浅析

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

SDI是Serialized Dictionary Information的缩写,是MySQL8.0重新设计数据词典后引入的新产物。我们知道MySQL8.0开始已经统一使用InnoDB存储引擎来存储表的元数据信息,但对于非InnoDB引擎,MySQL提供了另外一中可读的文件格式来描述表的元数据信息,在磁盘上以 $tbname.sdi的命名存储在数据库目录下。

你可以基于sdi文件来对非事务引擎表进行导出,导入操作,具体参阅官方文档

而对于InnoDB表没有创建sdi文件,而是将sdi信息冗余存储到表空间中(临时表空间和undo表空间除外)。

既然已经有了新的数据词典系统,为什么还需要冗余的sdi信息呢,这主要从几个方面考虑:

  • 当数据词典损坏时,实例可能拒绝启动,在这种情况下我们可以通过冗余的sdi信息,将数据拷贝到另外一个实例上,并进行数据重建
  • 可以离线的查看表的定义
  • 可以基于此实现简单的数据转储
  • MySQL Cluster/Ndb也可能依赖SDI信息进行元数据同步

官方提供了一个工具叫做ibd2sdi,在安装目录下可以找到,可以离线的将ibd文件中的冗余存储的sdi信息提取出来,并以json的格式输出到终端。

ibd2sdi工具的使用文档

相关worklog: WL#7069

下面简单的试玩下:

root@test 02:59:12>create table t1 (a int primary key, b char(10));
Query OK, 0 rows affected (0.02 sec)

通过ibd2sdi查看ibd文件

$bin/ibd2sdi data/test/t1.ibd
// 默认情况下打印所有信息
// 包含所有的列,索引的各个属性

也可以查询部分信息:

$bin/ibd2sdi --skip-data data/test/t1.ibd
["ibd2sdi"
,
{
        "type": 1,
        "id": 701
}
,
{
        "type": 2,
        "id": 235
}
]


$bin/ibd2sdi --id 235 data/test/t1.ibd
["ibd2sdi"
,
{
        "type": 2,
        "id": 235,
        "object":
                {
    "mysqld_version_id": 80011,
    "dd_version": 80011,
    "sdi_version": 1,
    "dd_object_type": "Tablespace",
    "dd_object": {
        "name": "test/t1",
        "comment": "",
        "options": "",
        "se_private_data": "flags=16417;id=212;server_version=80011;space_version=1;",
        "engine": "InnoDB",
        "files": [
            {
                "ordinal_position": 1,
                "filename": "./test/t1.ibd",
                "se_private_data": "id=212;"
            }
        ]
    }
}
}
]

当然还有很多其他的选项(ib2sdi --help),感兴趣的可以自行把玩。

首先ibd文件的第一个page中标记了是否存在sdi信息:FSP_FLAGS_POS_SDI,如果是从老版本(例如5.7)
物理恢复过来的数据,该标记位是未设置的。

在建表时,sdi相关堆栈如下:

ha_innobase::create
|--> innobase_basic_ddl::create_impl
    |--> create_table_info_t::create_table
        |--> create_table_info_t::create_table_def
            |--> row_create_table_for_mysql
                |--> dict_build_table_def
                    |--> dict_build_tablespace_for_table
                        |--> btr_sdi_create_index

btr_sdi_create_index:

  • 从代码来看,sdi index也是按照一个普通btree的标准函数(btr_create)来创建的,但其对应的page类型为FIL_PAGE_SDI
  • 内存中有一个和tablespace_id对应的dict_table_t对象,称作sdi table(dict_sdi_get_table), 表上包含4个列:

    • type
    • id
    • compressed_len
    • uncompressed_len
    • data(blob
  • sdi table的table_id从tablespace id中生成(dict_sdi_get_table_id)
  • sdi table上包含一个索引,索引列为(type, id), ref: dict_sdi_create_idx_in_mem
  • sdi pindex的root page no及sdi版本号被写到表空间的第一个page中(fsp_sdi_write_root_to_page)
  • 另外在之前版本中ibd文件的初始化大小为4个page,而到了8.0版本变成了7个page(FIL_IBD_FILE_INITIAL_SIZE),包括:
0: file space header
1: insert buffer bitmap
2: inode page
3: sdi index page
4: index page
5: freshly allocated page
6: freshly allocated page

在创建完table对象后,需要更新全局数据词典(create_table_info_t::create_table_update_global_dd)

写入tablespace信息到sdi中

innobase_basic_ddl::create_impl
|--> create_table_info_t::create_table_update_global_dd
    |--> dd_create_implicit_tablespace
        |--> create_dd_tablespace
            |--> dd::cache::Dictionary_client::store
                |--> dd::cache::Storage_adapter::store
                    |--> dd::sdi::store
                        |--> dd::sdi_tablespace::store_tsp_sdi
                            |--> dict_sdi_set

id=220

写入table信息到sdi中,包含了完整表的定义,每个列的属性信息等

ha_create_table
|-->dd::cache::Dictionary_client::update<dd::Table> 
    |-->dd::cache::Storage_adapter::store<dd::Table>
        |-->dd::sdi::store
            |-->dd::(anonymous namespace)::with_schema<long long unsigned int, dd::sdi::store
                |--> operator() 
                    |--> dd::sdi_tablespace::store_tbl_sdi
                        |--> apply_to_tablespaces //sdi_tablespace.cc:140
                            |--> ...
                                |--> dict_sdi_set
  • Server层提供的sdi接口:
[$/MySQL_8.0/sql/dd/impl]
$ls * | grep sdi
sdi_api.cc
sdi.cc
sdi_file.cc
sdi.h
sdi_impl.h
sdi_tablespace.cc
sdi_tablespace.h
sdi_utils.h
  • 构建sdi序列化词典信息的入口函数: dd::serialize, 这里会产生一个字符串,存储sdi信息
  • 调用innodb接口函数dict_sdi_set,将数据插入到其sdi index中,接口使用innodb api/api0api.cc(之前只由memcached使用)
  • 实际存储的数据是经过压缩的,压缩算法为zlib(Sdi_Compressor)
  • 向ibd中写入记录(ib_sdi_set),如果存在duplicate key,则更新记录
  • 之前介绍过sdi index中存在lob字段,其外部存储页的类型为FIL_PAGE_SDI_BLOB或者FIL_PAGE_SDI_ZBLOB
  • 当使用general tablespace时,sdi index中会存储多条数据
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
Transparent Data Encryption Data Dynamic and Data Dictionary Views You can query a set of dynamic and data dictionary views to find more information about Transparent Data Encryption (TDE) data.
Transparent Data Encryption Data Dynamic and Data Dictionary Views You can query a set of dynamic and data dictionary views to find more information about Transparent Data Encryption (TDE) data.
43 2
|
4月前
|
存储 Swift
在Swift编程语言中,字典(Dictionary)
在Swift编程语言中,字典(Dictionary)
64 3
|
11月前
|
存储 Java Python
多重字典(Multi-Level Dictionary)
多重字典(Multi-Level Dictionary)是一种将多个字典组合在一起的数据结构,用于解决需要在多个维度上查找数据的问题。多重字典可以看作是一个嵌套的字典,每个字典都可以作为其他字典的键。 使用多重字典的场景:
129 3
|
4月前
|
存储 缓存 数据库连接
Python基础教程——字典(Dictionary)
Python基础教程——字典(Dictionary)
|
3月前
|
存储 Python 容器
|
3月前
|
Python 存储 容器
Python 字典(Dictionary)
Python 字典(Dictionary)
|
4月前
|
开发者 Python
【Python 基础】递推式构造字典(dictionary comprehension)
【5月更文挑战第8天】【Python 基础】递推式构造字典(dictionary comprehension)
|
4月前
|
存储 数据处理 Python
Python中的字典(Dictionary)类型:深入解析与应用
Python中的字典(Dictionary)类型:深入解析与应用
38 0
|
4月前
|
存储 算法 数据库
Python字典(Dictionary)
Python字典(Dictionary)
41 0
|
4月前
|
存储 Swift
在Swift编程语言中,字典(Dictionary)
在Swift编程语言中,字典(Dictionary)
408 3