龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 数据库类 > MySQL 技术 >

深度解析Innodb记录格式源码

时间:2011-04-12 23:18来源:未知 作者:admin 点击:
分享到:
可以通过一个最普遍的插入操作来跟踪Innodb的记录格式,因为在插入时,系统得到的是公共的mysql记录格式record,现在它没有涉及到任何的存储引擎,那么这里不管当前这个表对应的存

可以通过一个最普遍的插入操作来跟踪Innodb的记录格式,因为在插入时,系统得到的是公共的mysql记录格式record,现在它没有涉及到任何的存储引擎,那么这里不管当前这个表对应的存储引擎是什么,记录格式是一样的,对于插入,mysql函数对应的是ha_write_row,具体到Innodb存储引擎,实际调用的函数是ha_innobase::write_row函数,那么在这里,Innodb首先会将接收到的record记录转换为它自己的一个元组tuple,这其实是与record对应的innodb的表示方式,它是一个内存的记录,逻辑的记录,那么在系统将其真正的写入到页面之前,这条记录的存在方式都是这个tuple,那么下面主要是从源码的角度研究Innodb是如何将一个tuple转换为它的物理的存储记录的,主要研究代码的实现逻辑及记录的格式。

这里只介绍格式为Compact类型的记录格式。

实现在某一个页面插入一个元组(一条记录)操作的函数是page_cur_tuple_insert,它的参数就是一个dtuple_t*类型的tuple,在这里,它首先要分配一片空间来存储将要转换过来的物理记录,所以这里需要先计算空间的大小,计算方法如下:

1. 首先每条记录都要包括下面2个部分:REC_N_NEW_EXTRA_BYTES + UT_BITS_IN_BYTES(n_null),前面表示的是这种格式的固定长度的extra部分,这部分用来存储什么内容后面会给出,后面表示的是所有字段中哪些字段的值是null,当然这里只存储那些nullable属于的字段,如果创建表的时候指定是not null的话,这里就不会被存储,那么这里是用一个位来表示一个字段的null属性。那么上面这部分被系统代码命名为extra_size变量值。

2. 统计每一个列中数据的长度,在统计这个信息的时候,又有多种情况,主要分定长字段和变长字段,对于定长字段,它的长度直接就是数据类型的长度,比如int类型的那就是4个字节,rowid列就是6个字节等,没有其它附加长度。对于变长字段而言,除了数据内容本身的长度外,还需要计算其数据长度的存储空间,如果字段的字义长度大于255个字节,或者字段的数据类型为BLOB的,那么需要用2个字节来存储这个字段的长度;如果定义长度小于128个字节,或者小于256个字节,但类型不是BLOB类型的,那么这个字段的数据长度用一个字节来存储,除上面2种情况之外,都用2个字节来存储。那么在这一部分中,用来存储变长字段数据的长度的空间的长度也是被Innodb计算为extra_size的。

所以现在可以知道,一个innodb的记录包括2个部分,一部分是extra_size,另一部分是数据内容,那么这2部分的总长度就是上面计算出来的结果,这里把它定义为record_size。

接下来,申请空间,进行元组到记录的转换工作。

转换函数为rec_convert_dtuple_to_rec_new,参数有申请好的记录空间buf,元组和索引的内存结构。

首先这里有一个操作是rec = buf + extra_size,变量rec表示的是数据内容的存储开始位置。extra_size就是上面计算出来的2个数据部分。

那么真正执行转换的是接下来调用的rec_convert_dtuple_to_rec_comp函数,下面是其原型:

  1. void 
  2.   
  3.  rec_convert_dtuple_to_rec_comp( 
  4.   
  5.  /*===========================*/ 
  6.   
  7.           rec_t*                          rec,   /*!< in: origin of record */ 
  8.   
  9.           ulint                    extra,        /*!< in: number of bytes to 
  10.   
  11.                                                 reserve between the record 
  12.   
  13.                                                 header and the data payload 
  14.   
  15.                                                 (normally REC_N_NEW_EXTRA_BYTES) */ 
  16.   
  17.           const dict_index_t*  index,        /*!< in: record descriptor */ 
  18.   
  19.           ulint                    status,       /*!< in: status bits of the record */ 
  20.   
  21.           const dfield_t*          fields,        /*!< in: array of data fields */ 
  22.   
  23.           ulint                    n_fields)/*!< in: number of data fields */ 

 

rec表示的是刚才上面计算出来的rec变量,extra表示的是固定长度的REC_N_NEW_EXTRA_BYTES。

 

  1. end = rec; 
  2.   
  3.           nulls = rec - (extra + 1); 
  4.   
  5.           n_null = index->n_nullable; 
  6.   
  7.           lens = nulls - UT_BITS_IN_BYTES(n_null); 
  8.   
  9.           /* clear the SQL-null flags */ 
  10.   
  11.           memset(lens + 1, 0, nulls - lens); 

在这里,这段代码一下子很难看明白,那么首先这里画一下记录存储格式:

精彩图集

赞助商链接