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, " ": { "mysqld_version_id": 80011, "dd_version": 80011, "sdi_version": 1, "dd_ _type": "Tablespace", "dd_ ": { "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_inno ::create|--> inno _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_indexbtr_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 header1: insert buffer bitmap2: inode page3: sdi index page4: index page5: freshly allocated page6: freshly allocated page在创建完table对象后,需要更新全局数据词典(create_table_info_t::create_table_update_global_dd)
写入tablespace信息到sdi中
inno _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_setid=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 sdisdi_api.ccsdi.ccsdi_file.ccsdi.hsdi_impl.hsdi_tablespace.ccsdi_tablespace.hsdi_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中会存储多条数据
继续阅读与本文标签相同的文章
sql server 临时表详细讲解及简单示例
mongodb基本操作使用大全
-
小程序如何引流?企业推广其实很简单
2026-05-19栏目: 教程
-
2019云栖大会 | 云原生时代 带你聚焦新数据库的硬核科技
2026-05-19栏目: 教程
-
AI人工智能了不得,帮助研究人员设计自行车,速度打破世界纪录
2026-05-19栏目: 教程
-
RNG官宣入驻快手,UZI成首席电竞官,S9成快手布局游戏圈跳板
2026-05-19栏目: 教程
-
国家邮政局官宣万国邮联国际小包终端费改革 你想知道的都在这里
2026-05-19栏目: 教程
