当 MemTable 的大小达到某个阈值后,OceanBase 数据库会将 MemTable 中的数据转存于磁盘上,转储后的结构称之为 SSTable。
宏块和微块
OceanBase 数据库将磁盘切分为大小为 2MB 的定长数据块,称之为宏块(Macro Block),宏块是数据文件写 IO 的基本单位,一个 SSTable 就由若干个宏块构成。在宏块内部数据被组织为多个大小为 16KB 左右的变长数据块,称之为微块(Micro Block),微块中包含若干数据行(Row),微块是数据文件读 IO 的最小单位。
宏块是定长的,大小为固定的 2MB,长度不可以被调整;微块是变长的,默认值为 16KB,指的是数据被压缩前的大小,数据压缩后通常大小会比指定的微块长度更小,同时 OceanBase 数据库在进行 IO 读取时,会按照 4KB 来做 IO 对齐,因此一次 IO 读的长度并不一定与微块长度完全一致。微块长度可以被修改,通过以下的语句可以对于不同的表设置不同的微块长度:
ALTER TABLE mytest SET block_size = 131072;
一般来说微块长度越大,数据的压缩比会越高,但相应的一次 IO 读的代价也会越大;微块长度越小,数据的压缩比会越低,但相应的一次 IO 读的代价会更小。微块的默认大小为 16KB。
随着数据的删除或者更新,一个宏块的数据填充可能不满,当相邻的几个宏块中的所有行可以在一个宏块中存放时,相邻的多个宏块会被合并成一个宏块。
编码与压缩
OceanBase 数据库通过数据编码压缩技术实现高压缩。数据编码是基于数据库关系表中不同字段的值域和类型信息,所产生的一系列的编码方式,它比通用的压缩算法更懂数据,从而能够实现更高的压缩效率。
按列压缩会比按行压缩更有效,这是因为关系表从列的方向去看,相邻字段由于具有相同数据类型和值域范围,其数据的相似性要远远好于从行的维度,所以 OceanBase 数据库是按照列进数据编码的。当一列经过编码后,成为定长存储时,OceanBase 数据库会对这一列在微块内使用列存进行存储。另外,OceanBase 数据库的读写分离架构使得数据总是批量写入磁盘,这种模式相比传统的脏页回刷磁盘的方式更加适合于数据压缩,开启编码后只会增加一部分数据后台合并的开销,对用户的实时写入、更新、删除性能是无损的,并且对部分查询性能有优化。这是因为编码后的数据不需要解码,就可以直接支持查询,而即使最快速的 lz4 压缩算法,也需要在数据访问前将整个数据块进行解压。另外,数据编码使得同一个数据块中能够容纳更多的数据,IO 的性能也随之提升。因此数据编码也是 OceanBase 数据表的默认选项。
OceanBase 数据库实现了多种数据编码方法,包括字典编码、RLE 编码、常量编码、差值编码、前缀编码、列间编码等,并根据数据特征自动为每一列选择最合适的数据编码,不需要用户来进行指定。在数据编码的基础上进一步对编码后的数据使用通用压缩算法进行压缩。通过编码和压缩,使用相同的块大小(16KB)、以及相同的压缩算法(lz4),同样的数据存放在 OceanBase 数据库中,和其他数据相比要平均节省超过一半的空间,同时没有损失任何性能。