SDI是Serialized Dictionary Information的缩写,是MySQL8.0重新设计数据词典后引入的新产物。我们知道MySQL8.0开始已经统一使用InnoDB存储引擎来存储表的元数据信息,但对于非InnoDB引擎,MySQL提供了另外一中可读的文件格式来描述表的元数据信息,在磁盘上以 $tbname.sdi的命名存储在数据库目录下。
你可以基于sdi文件来对非事务引擎表进行导出,导入操作,具体参阅官方文档
而对于InnoDB表没有创建sdi文件,而是将sdi信息冗余存储到表空间中(临时表空间和undo表空间除外)。
既然已经有了新的数据词典系统,为什么还需要冗余的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:
btr_create
)来创建的,但其对应的page类型为FIL_PAGE_SDI
内存中有一个和tablespace_id对应的dict_table_t对象,称作sdi table(dict_sdi_get_table
), 表上包含4个列:
dict_sdi_get_table_id
)dict_sdi_create_idx_in_mem
fsp_sdi_write_root_to_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::cache::Storage_adapter::store
|-->dd::sdi::store
|-->dd::(anonymous namespace)::with_schema operator()
|--> dd::sdi_tablespace::store_tbl_sdi
|--> apply_to_tablespaces //sdi_tablespace.cc:140
|--> ...
|--> dict_sdi_set
[$/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
dd::serialize
, 这里会产生一个字符串,存储sdi信息Sdi_Compressor
)ib_sdi_set
),如果存在duplicate key,则更新记录