前一篇讨论了Innodb system,表空间,文件的关系及数据结构,这一篇记录下Innodb行记录的格式。

前提:
  1. server层和innodb层都有自己对于record的记录格式,需要进行转换。
  2. 物理文件上的记录存储,需要内存中的数据结构进行对应(任何数据都需要在内存中进行处理),进行存取的转换。

1. 测试case:

 create table `pp` (
`id` int() default null,
`name1` varchar() default null,
`name2` char() default null
) engine=innodb default row_format: compact insert into pp values(,'xpchild1','xpchild2');

2. 重要的数据结构:

  

    struct row_prebuilt_struct{
mysql_row_templ_t* mysql_template;  server层的记录格式
ins_node_t* ins_node;        innodb层的数据结构
} /* Insert node structure */
struct ins_node_struct{
dtuple_t* row;            写入的行row
}
/** Structure for an SQL data tuple of fields (logical record) */
struct dtuple_struct {
dfield_t fields;            row记录的fields列表
}
/** Structure for an SQL data field */
struct dfield_struct{
void *data;                row记录中一个字段的定义
}

2. 写入及转换过程:

  1. 准备过程:

    简要记录一下:

    1.1: 进入并发控制:进入innodb层的线程受限制,排队进入
        innodb_srv_conc_enter_innodb(prebuilt->trx);
    1.2: 创建node && row元组数据结构
        node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
        row = dtuple_create(prebuilt->heap,dict_table_get_n_cols(table));
    1.3: 判断是否是compact格式: dict_table_is_comp(prebuilt->table)

  2. 内存--内存之间的转换: mysql server层到innodb层

    row_mysql_convert_row_to_innobase:

    for (i = 0; i < prebuilt->n_template; i++)
      templ = prebuilt->mysql_template + i;    从mysql层取出来temp1,
      dfield = dtuple_get_nth_field(row, i);    从row中取出来dfield,
      row_mysql_store_col_in_innobase_format(....);  然后用temp1去填充。

    

  3. 内存->磁盘文件的转换:转换tuple到记录rec

    先来看一下innodb存储的格式:

      

    说明:

1. len_arr: 记录的是变长column的长度,定长的不记录。
2. null_bits: 记录哪一个column是null值,因为null的column不占用其他空间
3. extra_bytes: 一共5个字节,记录了: Deleted_flag, Min_rec_flag, N_owned, Next_recorder等信息。
4. row_id: 因为innodb使用聚簇索引表,如果定义了pk,这里就是pk的值,如果没有,innodb会自动生成一个row_id.
5. trx_id: 记录事务id
6. roll_ptr: 回滚段地址,用于回滚和mvcc
7. id, name1, name2表示表pp的字段值

    3.1 分配row_id:
        row_ins_alloc_row_id_step: 判断是否是pk cluster表。
        如果不是,就分配一个rowid。dict_sys_get_new_row_id,
        然后填充到dict_sys_write_row_id(node->row_id_buf, row_id);

    

    3.2 生成系统index
      node->index = dict_table_get_first_index(node->table);
      系统自动为没有index的表,生成了一个叫GEN_CLUST_INDEX的index。本身不存在。
        /* "GEN_CLUST_INDEX" is the name reserved for Innodb default system primary index. */

    

    3.3 计算rec的长度:
        extra_size = REC_N_NEW_EXTRA_BYTES + UT_BITS_IN_BYTES(index->n_nullable);
        这里计算的extra_size=6,
        null_bits的计算方式是:#define UT_BITS_IN_BYTES(b) (((b) + 7) / 8)

        遍历每一个column,计算column的长度占用的空间,以及存储数据所需要的空间。

条件1:fixed_length不占用len_arr.
条件2:如果是变长,且定义的最大长度< =255, 则len占用1个bytes。
条件3:如果是变长,且定义的长度>255, 但实际长度<128,则len占用1个bytes。
条件4: 如果是变长,且定义的长度>255, 但实际长度>=128,或者overflow了,则len占用2个bytes

/* If the maximum length of a variable-length field
is up to 255 bytes, the actual length is always stored
in one byte. If the maximum length is more than 255
bytes, the actual length is stored in one byte for
0..127. The length will be encoded in two bytes when
it is 128 or more, or when the field is stored externally. */ if (field->fixed_len) {
ut_ad(len == field->fixed_len);
/* dict_index_add_col() should guarantee this */
ut_ad(!field->prefix_len
|| field->fixed_len == field->prefix_len);
} else if (dfield_is_ext(&fields[i])) {
ut_ad(col->len >= || col->mtype == DATA_BLOB);
extra_size += ;
} else if (len <
|| (col->len < && col->mtype != DATA_BLOB)) {
extra_size++;
} else {
/* For variable-length columns, we look up the
maximum length from the column itself. If this
is a prefix index column shorter than 256 bytes,
this will waste one byte. */
extra_size += ;
}

  

  注意:之所以对于定义>255的,可能使用1个或者2个字节,兼顾了空间使用的效率。

      最终计算出来的结果是:len_arr=1; null_bits=1;

  

  3.4 写入rec内容:
    根据前面获取的size,然后把字段的内容写入的buf中,最后写入到page中。

  

注意: varchar 在使用的时候,并不是大于255就一定会使用2个字节存储长度。 所以varchar(>255)比小于255的多使用空间的说法,在compact格式下,是不准确的。

------------------------------------------------------------------------------------------------------------------------------------------------------

后记:  对于定义>255的column,可能使用1bytes,也可能使用2bytes来保存length,但究竟是如何存储的,读的时候又如何判断的呢?

下面来看下三个case:

  1. 如果column定义>255 , actual length<128,则使用1bytes,8bit的最高为是0

  2. 如果column定义>255,actual length>128 && <16384, 则使用2 bytes, 最后len |=0x80, 使最高位=1

  3. 如果column定义>255, actual length >16384,则使用2 bytes, 最后len|=0xc0。 使最高两位都=1

所以,究竟是一个字节还是两个字节,在读的时候,使用最高位,如果是0,就是一个字节,如果是1,就是两个字节。

假如column是65535,最高位需要表示长度,才能够表示出来65535这么大的数? 为什么最高位没有拿来使用,而是作为标志位呢?

问题的关键就在16384, 即16k,一个page的大小是16k,所以65535需要overflow才能保存,所以,两个字节的高两位,根本不用用来保存长度,而作为标志位来使用。

   

Innodb物理存储结构系列2 行记录格式的更多相关文章

  1. Innodb物理存储结构系列1

    本篇先介绍 下Innodb表空间,文件相关的内存数据结构. 1. 数据结构 Innodb的tablespace和文件的关系,是一对多的关系,先来看三个结构体 1. fil_system_struct: ...

  2. InnoDB表存储结构及keyring加密

    ibdata是InnoDB最重要的系统表空间文件,它记录了InnoDB的核心信息,包括事务系统信息.元数据信息,记录InnoDB change buffer的btree,防止数据损坏的double w ...

  3. InnoDB的表类型,逻辑存储结构,物理存储结构

    表类型 对比Oracle支持的各种表类型,InnoDB存储引擎表更像是Oracle中的索引组织表(index organized table).在InnoDB存储引擎表中,每张表都有个主键,如果在创建 ...

  4. InnoDB 逻辑存储结构

    本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/80 如果创建表时没有显示的定义主键,mysql会按如下方式创建主 ...

  5. Innodb页面存储结构-2

    上一篇<Innodb页面存储结构-1>介绍了Innodb页面存储的总体结构,本文会介绍页面的详细内容,主要包括页头.页尾和记录的详细格式. 学习数据结构时都说程序等于数据结构+算法,而在i ...

  6. InnoDB数据存储结构

    MySQL服务器上 存储引擎 负责对表中数据的读取和写入工作,不同存储引擎中 存放的格式 一般是不同的,甚至有的存储引擎(Memory)不用磁盘来存储数据. 页 (Page) 是磁盘和内存之间交互的基 ...

  7. innodb的存储结构

    如下所示,innodb的存储结构包含:表空间,段,区,页(块),行 innodb存储结构优化的标准是:一个页里面存放的行数越多,其性能越高 表空间:零散页+段 独立表空间存放的是:数据.索引.插入缓冲 ...

  8. MySQL InnoDB 逻辑存储结构

    MySQL InnoDB 逻辑存储结构 从InnoDB存储引擎的逻辑结构看,所有数据都被逻辑地存放在一个空间内,称为表空间,而表空间由段(sengment).区(extent).页(page)组成.p ...

  9. Atitit.数据库表的物理存储结构原理与架构设计与实践

    Atitit.数据库表的物理存储结构原理与架构设计与实践 1. Oracle和DB2数据库的存储模型如图: 1 1.1. 2. 表数据在块中的存储以及RowId信息3 2. 数据表的物理存储结构 自然 ...

随机推荐

  1. WPF编程学习——布局

    本文目录 1.布局简介 2.面板(Panel) 3.视图框(Viewbox) 4.滚动视图控件(ScrollViewer) 5.公共布局属性 1.布局简介 应用程序界面设计中,合理的元素布局至关重要, ...

  2. HDOJ1050

    Moving Tables Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  3. (链接保存)CentOS 6.6下yum快速升级内核

    (因Docker建议3.8以上kernel版本)这个方法升级很方便,保存链接备用: http://www.dadclab.com/archives/5340.jiecao Docker Engine安 ...

  4. Sqli-labs less 15

    Less-15 本关没有错误提示,那么我们只能靠猜测进行注入.这里我直接从源代码中看到了sql语句 @$sql="SELECT username, password FROM users W ...

  5. 对于Linux平台下C语言开发中__sync_函数的认识

      reference:http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html#Atomic-Builtins A built ...

  6. POJ 2724

    Purifying Machine Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4014   Accepted: 1127 ...

  7. 能够将 HTML 表格转换成图表的jQuery插件:Chartinator

    点这里 一个jQuery 插件能够将HTML 表格转换成图表,使用 Google Charts 实现. Chartinator当前支持以下特性: Creation of the following c ...

  8. IDA 使用技巧

    我用的IDA Pro 6.5,把我自己使用ida的一些方法记录,免得自己遗忘 1 .导入符号表 可以像前一篇博客中写的那样,也可以使用File--->LoadFile--->PDB Fil ...

  9. java中静态代理跟动态代理之间的区别

    文章转载于:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另 ...

  10. python_pycharm介绍1

    1. 常用设置 修改编程风格 File-Setting中,Editor下Colors&Fonts修改即可调整风格. 修改字体大小 pycharm默认字体太小,需调整些,Settings--&g ...