Innodb 中的 Blob

前言


Innodb 使用的是B-tree 的形式来存储数据,这就意味着如果一个record 超过了单个page 的大小就没办法有效的索引。然而事实上blob 这种数据类型就是需要在一个record 里面存储相当大的数据。Innodb 内部使用了外部存储的方法来实现blob 的存储。在cluster record 里面只存储blob 的reference 索引,通常只有20bytes,通过这个索引会直接定位到外部存储的数据位置。这样解决了B-tree 不能够对于big record 高效索引的问题。这里基于Mysql 8.0.26 介绍了Blob 存储使用的各种物理数据结构,然后就其Insert ,Update,Delete 等接口进行详细的代码解析。最后对于Blob 的partical update 的优化进行了分析。

需要说明的是,8.0 版本对于blob 这种数据类型进行了比较大的重构,主要支持了Partical Update 的优化,与5.6 和 5.7 版本的blob 的物理数据结构有比较大的变动。这里的数据结构并不适用于5.6 跟5.7 版本。


数据结构


Blob 物理数据类型在内核中定义了三种page 类型,分别是first page ,index page 和data page,同时其在cluster key 当中存储的并不是真正的数据,只是自己定义的一个reference 。下边是各个数据类型的详细解释。

1,First page


first_page_t FIL_PAGE_DATA = 38; OFFSET_VERSION = FIL_PAGE_DATA; 1byte(没什么用) OFFSET_FLAGS = FIL_PAGE_DATA + 1; (mark can be partially updated) OFFSET_LOB_VERSION = OFFSET_FLAGS + 1; 4bytes OFFSET_LAST_TRX_ID = OFFSET_LOB_VERSION + 4; 6bytes(最后一次修改这个page 的trx id) OFFSET_LAST_UNDO_NO = OFFSET_LAST_TRX_ID + 6;4bytes(最后一次修改这个page 的trx no) OFFSET_DATA_LEN = OFFSET_LAST_UNDO_NO + 4; 4bytes OFFSET_TRX_ID = OFFSET_DATA_LEN + 4; 6bytes (初始化first page 的时候用的trx id) OFFSET_INDEX_LIST = OFFSET_TRX_ID + 6; index_list 4Bytes FLST_LEN 0 /* 32-bit list length field */ 4bytes 6Bytes FLST_FIRST 4 /* (space + offset)of the first element of the list; undefined if empty list */ 6Bytres FLST_LAST (4 + FIL_ADDR_SIZE) /* the last element of the list; undefined if empty list */ OFFSET_INDEX_FREE_NODES = OFFSET_INDEX_LIST + FLST_BASE_NODE_SIZE(4+ 2*6); free list 4Bytes FLST_LEN 0 6Bytes FLST_FIRST 4 6Bytres FLST_LAST (4 + FIL_ADDR_SIZE) LOB_PAGE_DATA = OFFSET_INDEX_FREE_NODES + FLST_BASE_NODE_SIZE(4+ 2*6); 10 index entries(by default), each index entry is of size 60 bytes. (10* 60 = 600bytes) index entry1 index entry2 ... index entry10 data_begin()=frame()+LOB_PAGE_DATA+node_count()*index_entry_t::SIZE (10*60); LOB_PAGE_TRAILER_LEN = FIL_PAGE_DATA_END;