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;