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

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

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中会存储多条数据
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
24天前
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.
11 2
|
3月前
|
存储 Swift
在Swift编程语言中,字典(Dictionary)
在Swift编程语言中,字典(Dictionary)
34 3
|
6月前
|
存储 Java Python
多重字典(Multi-Level Dictionary)
多重字典(Multi-Level Dictionary)是一种将多个字典组合在一起的数据结构,用于解决需要在多个维度上查找数据的问题。多重字典可以看作是一个嵌套的字典,每个字典都可以作为其他字典的键。 使用多重字典的场景:
44 3
|
1月前
|
存储 算法 数据库
Python字典(Dictionary)
Python字典(Dictionary)
11 0
|
3月前
|
存储 缓存 数据库
python中的字典(Dictionary)
python中的字典(Dictionary)
18 0
|
3月前
|
存储 Swift
在Swift编程语言中,字典(Dictionary)
在Swift编程语言中,字典(Dictionary)
297 3
|
3月前
|
Python
在Python中,字典(dictionary)的键(key)具有唯一标识性
在Python中,字典(dictionary)的键(key)具有唯一标识性
47 1
|
3月前
|
存储 Python
在Python中,字典(Dictionary)
在Python中,字典(Dictionary)
28 1
|
4月前
|
存储 JSON Shell
Python(十八)python字典dictionary
Python中的字典和json对象类似,都是键值对存储数据。 但是,其二者是有区别的。只是类似,并不一样。 字典和json的区别,后边会单独提到。 Python字典: 1. 字典是列表之外另一种可变容器模型,且可存储任意类型对象。 2. 字典以键值对{key:value}形式存储。 3. 键必须是唯一的,不允许同一个键出现两次。但值则不必。 **4. ** 值可以取任何数据类型,但键必须是不可变的,如字符串,数字。 **5. ** 定义字典使用一对大括号 {} 来定义。 **6. ** 字典是一个无序的数据集合,我们更关心key对应的值,而不是关心其存储的顺
54 0
|
7月前
|
C#
C#中字典Dictionary的用法详解
C#中字典Dictionary的用法详解