您现在的位置是:网站首页> 编程资料编程资料

MySQL Innodb 存储结构 和 存储Null值 用法详解_Mysql_

2023-05-27 415人已围观

简介 MySQL Innodb 存储结构 和 存储Null值 用法详解_Mysql_

背景:

表空间:INNODB 所有数据都存在表空间当中(共享表空间),要是开启innodb_file_per_table,则每张表的数据会存到单独的一个表空间内(独享表空间)。
独享表空间包括:数据,索引,插入缓存,数据字典。共享表空间包括:Undo信息(不会回收<物理空间上>),双写缓存信息,事务信息等。
段(segment):组成表空间,有区组成。
区(extent):有64个连续的页组成。每个页16K,总共1M。对于大的数据段,每次最后可申请4个区。
页(page):是INNODB 磁盘管理的单位,有行组成。
行(row):包括事务ID,回滚指针,列信息等。

目的1:
了解表空间各个页的信息和溢出行数据存储的信息。通过该书作者蒋承尧编写的工具:http://code.google.com/p/david-mysql-tools/source/browse/trunk/py_innodb_page_type/
3个脚本:

py_innodb_page_info.py

 View Code #! /usr/bin/env python #encoding=utf-8 import mylib from sys import argv from mylib import myargv if __name__ == '__main__': myargv = myargv(argv) if myargv.parse_cmdline() == 0: pass else: mylib.get_innodb_page_type(myargv)

mylib.py

 View Code encoding=utf-8 import os import include from include import * TABLESPACE_NAME='D:\\mysql_data\\test\\t.ibd' VARIABLE_FIELD_COUNT = 1 NULL_FIELD_COUNT = 0 class myargv(object): def __init__(self, argv): self.argv = argv self.parms = {} self.tablespace = '' def parse_cmdline(self): argv = self.argv if len(argv) == 1: print 'Usage: python py_innodb_page_info.py [OPTIONS] tablespace_file' print 'For more options, use python py_innodb_page_info.py -h' return 0 while argv: if argv[0][0] == '-': if argv[0][1] == 'h': self.parms[argv[0]] = '' argv = argv[1:] break if argv[0][1] == 'v': self.parms[argv[0]] = '' argv = argv[1:] else: self.parms[argv[0]] = argv[1] argv = argv[2:] else: self.tablespace = argv[0] argv = argv[1:] if self.parms.has_key('-h'): print 'Get InnoDB Page Info' print 'Usage: python py_innodb_page_info.py [OPTIONS] tablespace_file\n' print 'The following options may be given as the first argument:' print '-h help ' print '-o output put the result to file' print '-t number thread to anayle the tablespace file' print '-v verbose mode' return 0 return 1 def mach_read_from_n(page,start_offset,length): ret = page[start_offset:start_offset+length] return ret.encode('hex') def get_innodb_page_type(myargv): f=file(myargv.tablespace,'rb') fsize = os.path.getsize(f.name)/INNODB_PAGE_SIZE ret = {} for i in range(fsize): page = f.read(INNODB_PAGE_SIZE) page_offset = mach_read_from_n(page,FIL_PAGE_OFFSET,4) page_type = mach_read_from_n(page,FIL_PAGE_TYPE,2) if myargv.parms.has_key('-v'): if page_type == '45bf': page_level = mach_read_from_n(page,FIL_PAGE_DATA+PAGE_LEVEL,2) print "page offset %s, page type <%s>, page level <%s>"%(page_offset,innodb_page_type[page_type],page_level) else: print "page offset %s, page type <%s>"%(page_offset,innodb_page_type[page_type]) if not ret.has_key(page_type): ret[page_type] = 1 else: ret[page_type] = ret[page_type] + 1 print "Total number of page: %d:"%fsize for type in ret: print "%s: %s"%(innodb_page_type[type],ret[type])

include.py

 View Code #encoding=utf-8 INNODB_PAGE_SIZE = 16*1024*1024 # Start of the data on the page FIL_PAGE_DATA = 38 FIL_PAGE_OFFSET = 4 # page offset inside space FIL_PAGE_TYPE = 24 # File page type # Types of an undo log segment */ TRX_UNDO_INSERT = 1 TRX_UNDO_UPDATE = 2 # On a page of any file segment, data may be put starting from this offset FSEG_PAGE_DATA = FIL_PAGE_DATA # The offset of the undo log page header on pages of the undo log TRX_UNDO_PAGE_HDR = FSEG_PAGE_DATA PAGE_LEVEL = 26 #level of the node in an index tree; the leaf level is the level 0 */ innodb_page_type={ '0000':u'Freshly Allocated Page', '0002':u'Undo Log Page', '0003':u'File Segment inode', '0004':u'Insert Buffer Free List', '0005':u'Insert Buffer Bitmap', '0006':u'System Page', '0007':u'Transaction system Page', '0008':u'File Space Header', '0009':u'扩展描述页', '000a':u'Uncompressed BLOB Page', '000b':u'1st compressed BLOB Page', '000c':u'Subsequent compressed BLOB Page', '45bf':u'B-tree Node' } innodb_page_direction={ '0000': 'Unknown(0x0000)', '0001': 'Page Left', '0002': 'Page Right', '0003': 'Page Same Rec', '0004': 'Page Same Page', '0005': 'Page No Direction', 'ffff': 'Unkown2(0xffff)' } INNODB_PAGE_SIZE=1024*16 # InnoDB Page 16K

测试1:

 root@localhost : test 02:26:13>create table tt(id int auto_increment,name varchar(10),age int,address varchar(20),primary key (id))engine=innodb; Query OK, 0 rows affected (0.17 sec) root@zhoujy:/var/lib/mysql/test# ls -lh tt.ibd -rw-rw---- 1 mysql mysql 96K 2012-10-17 14:26 tt.ibd

查看ibd:

 root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v page offset 00000000, page type  page offset 00000001, page type  page offset 00000002, page type  page offset 00000003, page type , page level <0000> ---叶子节点 page offset 00000000, page type  page offset 00000000, page type  Total number of page: 6: Freshly Allocated Page: 2 Insert Buffer Bitmap: 1 File Space Header: 1 B-tree Node: 1 File Segment inode: 1

解释:
Total number of page: 总页数
Freshly Allocated Page:可用页
Insert Buffer Bitmap:插入缓存位图页
Insert Buffer Free List:插入缓存空闲列表页
B-tree Node:数据页
Uncompressed BLOB Page:二进制大对象页,存放溢出行的页,即溢出页
上面得到的信息是表初始化大小为96K,他是有 Total number of page * 16 得来的。1个数据页,2个可用页面。

 root@localhost : test 02:42:58>insert into tt values(name,age,address) values('aaa',23,'HZZZ'); 

疑惑:为什么没有申请区?区是64个连续的页,大小1M。那么表大小也应该是至少1M。但是现在只有96K(默认)。原因是因为每个段开始的时候,先有32个页大小的碎片页存放数据,使用
完之后才是64页的连续申请,最多每次可以申请4个区,保证数据的顺序。这里看出表大小增加是按照至少64页的大小的空间来增加的,即1M增加。
验证:
填充数据,写满这32个碎片页,32*16 = 512K。看看是否能申请大于1M的空间。

 View Code root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd -rw-rw---- 1 mysql mysql 576K 2012-10-17 15:30 /var/lib/mysql/test/tt.ibd root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v page offset 00000000, page type  page offset 00000001, page type  page offset 00000002, page type  page offset 00000003, page type , page level <0001> page offset 00000004, page type , page level <0000> page offset 00000005, page type , page level <0000> page offset 00000006, page type , page level <0000> page offset 00000007, page type , page level <0000> page offset 00000008, page type , page level <0000> page offset 00000009, page type , page level <0000> page offset 0000000a, page type , page level <0000> page offset 0000000b, page type , page level <0000> page offset 0000000c, page type , page level <0000> page offset 0000000d, page type , page level <0000> page offset 0000000e, page type , page level <0000> page offset 0000000f, page type , page level <0000> page offset 00000010, page type , page level <0000> page offset 00000011, page type , page level <0000> page offset 00000012, page type , page level <0000> page offset 00000013, page type , page level <0000> page offset 00000014, page type , page level <0000> page offset 00000015, page type , page level <0000> page offset 00000016, page type , page level <0000> page offset 00000017, page type , page level <0000> page offset 00000018, page type , page level <0000> page offset 00000019, page type , page level <0000> page offset 0000001a, page type , page level <0000> page offset 0000001b, page type , page level <0000> page offset 0000001c, page type , page level <0000> page offset 0000001d, page type , page level <0000> page offset 0000001e, page type , page level <0000> page offset 0000001f, page type , page level <0000> page offset 00000020, page type , page level <0000> page offset 00000021, page type , page level <0000> page offset 00000022, page type , page level <0000> page offset 00000023, page type , page level <0000> Total number of page: 36: Insert Buffer Bitmap: 1 File Space Header: 1 B-tree Node: 33 File Segment inode: 1

"额外"页:4个
page offset 00000000, page type :文件头空间页
page offset 00000001, page type :插入缓存位图页
page offset 00000002, page type :文件段节点
page offset 00000003, page type , page level <0001>:根页
碎片页:32个
page type , page level <0000>
总共36个页,ibd大小 576K的由来:32*16=512K(碎片页)+ 4*16=64(额外页),这里开始要是再插入的话,应该申请最少1M的页:

 root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd -rw-rw---- 1 mysql mysql 2.0M 2012-10-17 16:10 /var/lib/mysql/test/tt.ibd root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd Total number of page: 128: Freshly Allocated Page: 91 Insert Buffer Bitmap: 1 File Space Header: 1 B-tree Node: 34 File Segment inode: 1

页从36跳到了128,因为已经用完了32个碎片页,新的页会采用区的方式进行空间申请。信息中看到有很多可用页,正好说明这点。

▲溢出行数据存放:INNODB存储引擎是索引组织的,即每页中至少有两行记录,因此如果页中只能存放一行记录,INNODB会自动将行数据放到溢出页中。当发生溢出行的时候,实际数据保存在BLOB页中,数据页只保存数据的前768字节(老的文件格式),新的文件格式(Barracuda)采用完全行溢出的方式,数据页只保存20个字节的指针,BLOB也保存所有数据。如何查看表中有溢出行数据呢?

 root@localhost : test 04:52:34>create table t1 (id int,name varchar(1
                
                

-六神源码网