前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MYSQL INNODB ibd文件详解 (3) FIL_PAGE_SDI

MYSQL INNODB ibd文件详解 (3) FIL_PAGE_SDI

原创
作者头像
大大刺猬
发布2023-04-25 13:29:57
7270
发布2023-04-25 13:29:57
举报
文章被收录于专栏:大大刺猬大大刺猬

虽然上一章已经提取了DDL, 但是存储DDL的sdi页还没有讲.... 现在补上呗..

FIL_PAGE_SDI

是存储数据字典的, 8.0把它和表放一起了. 位于ibd文件的第4页 (在inode里面有记录, 也是属于segment)

结构如下

名字

大小(字节)

描述

FIL_HEADER

38

PAGE_HEADER

56

页头部信息

INFIMUM

13

rec_header(5)+infimum(8) 指向下一条记录

SUPREMUM

13

rec_header(5)+supremum(8) 最后一条记录

other

SDI_DATA

SDI数据, 使用zlib压缩存储的.

other(比如page_directory)

FIL_TRAILER

8

INFIMUM记录的地址不包含RECORD_HEADER
INFIMUM记录的地址不包含RECORD_HEADER

PYTHON解析SDI

sdi信息里面并没有唯一索引的区别, 只有主键索引和普通索引, 推测唯一约束由server层实现.

代码语言:javascript
复制
import innodb_sdi
aa = innodb_sdi.sdi('/data/mysql_3314/mysqldata/db1/ddcw_benchmark__12.ibd')
print(aa.get_ddl())
#aa.get_dic() #返回字典

总结

sdi_page比较简单, 就是个zlib压缩的json格式数据.

ordinal_position 表示的是字段顺序. cloumns和indexes中ordinal_position是完全对应的.

indexes中elements的length如果是4294967295(4G)就表示这个值不属于KEY(就是不是索引值, 是其它值/主键值)

附PYTHON源码

innodb_sdi.py

注: 无法区别是否为唯一索引.

代码语言:javascript
复制
#解析sdi page
#storage/innobase/dict/dict0crea.cc

#STRUCT:
#FIL_HEADER 38
#PAGE_HEADER 56
#INFIMUM 13 (5+8) rec_header的最后两字节指向 sdi数据位置

import struct,json,zlib

PAGE_NEW_INFIMUM = 99

PAGE_SIZE = 16384
class sdi(object):
	def __init__(self,tdata):
		bdata = tdata
		if len(tdata) != PAGE_SIZE:
			with open(tdata,'rb') as f:
				f.seek(PAGE_SIZE*3,0)
				bdata = f.read(PAGE_SIZE)
		self.bdata = bdata
		self.dic_info = None
		self.HAS_NULL = True #设置空值 for ddl
		self.HAS_DEFAULT = True #设置默认值 for ddl
		self.HAS_COMMENT = True #设置注释
		self.HAS_IF_NOT_EXISTS = False #不要create table if not exists

	def get_index(self,):
		return self.get_dic()['dd_object']['indexes']

	def get_columns(self,):
		return self.get_dic()['dd_object']['columns']

	def get_version(self,):
		return self.get_dic()['mysqld_version_id']

	def get_name(self,):
		dic_info = self.get_dic()
		return f"{dic_info['dd_object']['schema_ref']}.{dic_info['dd_object']['name']}"

	def get_ddl(self):
		dic_info = self.get_dic()
		columns = dic_info['dd_object']['columns']
		indexes = dic_info['dd_object']['indexes']
		dd_object_type = dic_info['dd_object_type']
		schema = dic_info['dd_object']['schema_ref']
		engine = dic_info['dd_object']['engine']
		comment = dic_info['dd_object']['comment']
		foreign_keys = None #不支持外键
		name = dic_info['dd_object']['name']

		ddl = f"CREATE {dd_object_type} {'IF NOT EXISTS' if self.HAS_IF_NOT_EXISTS else '' } {schema}.{name}"
		cols = ''
		coll = {}
		for col in columns:
			if col['name'] in ['DB_TRX_ID','DB_ROLL_PTR','DB_ROW_ID']:
				continue
			coll[col['ordinal_position']] = col['name']
			cols += f"\n{col['name']} {col['column_type_utf8']} {'NULL' if col['is_nullable'] else 'NOT NULL' if self.HAS_NULL else ''} { col['default_value_utf8'] if self.HAS_DEFAULT else '' } { col['comment'] if self.HAS_COMMENT else ''},"
		indexl = []
		for i in indexes:
			index_name = "PRIMARY KEY" if i['name'] == 'PRIMARY' else i['name']
			idxl = []
			for x in i['elements']:
				if x['length'] < 4294967295:
					idxl.append(x['ordinal_position'])
			if len(idxl) == 0:
				continue
			indexl.append(f'{index_name}({",".join([ coll[x] for x in idxl ])})')
		index = ",".join([ x for x in indexl ])
		col_index = f"{cols}\n{index}" if len(index) > 0 else f"{cols[:-1]}"
		ddl = f"{ddl}({col_index}) ENGINE={engine} {comment if self.HAS_COMMENT else ''};"

		return ddl

	def get_dic(self):
		offset = struct.unpack('>H',self.bdata[PAGE_NEW_INFIMUM-2:PAGE_NEW_INFIMUM])[0] + PAGE_NEW_INFIMUM
		dtype,did = struct.unpack('>LQ',self.bdata[offset:offset+12])
		dtrx = int.from_bytes(self.bdata[offset+12:offset+12+6],'big')
		dundo = int.from_bytes(self.bdata[offset+12+6:offset+12+6+7],'big')
		dunzip_len,dzip_len = struct.unpack('>LL',self.bdata[offset+33-8:offset+33]) 

		unzbdata = zlib.decompress(self.bdata[offset+33:offset+33+dzip_len])
		dic_info = json.loads(unzbdata.decode())
		return dic_info if len(unzbdata) == dunzip_len else {}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • FIL_PAGE_SDI
  • PYTHON解析SDI
  • 总结
  • 附PYTHON源码
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档