概况
rocksdb作为KV存储引擎,那么myrocks记录最终会以kv的形式存储在rocksdb中。MySQL中的表一般由若干索引组成, 在innodb存储引擎中,每个索引对应一颗B树,而在rocksdb存储引擎中,索引对应于rocksdb中一段连续范围的数据。
具体来说,这个范围是此索引id和id+1之间的所有数据。如果表的所有索引都在一个column family, 那表的这些索引数据在物理上基本是连续的。
可以参考之前文章中的图示
myrocks记录格式
myrocks以索引为单位,将表的所有索引分别存储在rocksdb中。
根据索引的类型,myrocks记录的格式有所不同。下面以下表不同索引类型来分别介绍
CREATE TABLE t1(a INT, b VARCHAR(20), c char(5), d int, pk INT AUTO_INCREMENT, PRIMARY KEY(pk) comment 'cf_1', unique key idx2(b) comment 'cf_2') engine= rocksdb; INSERT INTO t1 (pk,a,b,c) VALUES (1,1,'bbbbbbbbbb','c');
-
主键
主键索引记录kv结构如下key: index_id, M(pk) value: unpack_info, NULL-bitmap,b,c,d
key由索引id和主键组成。 index_id是索引的唯一标识占用4个字节,M(pk) 表示pk转化后的数据,此转化后的数据可以直接用于memcmp比较
rocksdb数据都是根据key排序的,为了便于比较,不同类型数据都会经过一些转化,转化后可以直接用于memcmp比较。
关于memcmp转化,下一节会详细介绍value存储unpack_info和非主键外的其他字段数据, Null-bitmap标识哪些字段为空。
unpace_info存储将M(pk)逆转化为pk的信息,如果不需要额外转换信息则unpace_info为null,此例中pk为int类型,不需要额外信息unpace_info为null -
二级索引 idx2
二级索引记录kv结构如下key: index_id,NULL-byte, M(b),M(pk) value: unpack_info
key由index_id,二级索引键和主键组成, 其中NULL-byte表示b是否为空。pk为主键非空,所以不需要NULL-byte
value只有unpack_info,表示 M(b),M(pk)逆转化信息,如果不需要额外转换信息则unpace_info为null。此例中b为varchar类型,需要额外信息unpace_info不为null唯一索引和普通二级索引存储方式没有区别
联合索引每多一个字段会在字段前增加一个NULL-byte,来表示此字段是否为空
Memcomparable format
rocksdb为了比较方便,将key字段转化为可以直接memcmp比较的形式。所以MyRocks 一般建议使用sensitive collations (latin1_bin, utf8_bin, binary).
这样可以避免转化的开销。
- 整形
整形转化比较简单,但对于有符号类型需要特殊处理,如果直接存储会导致比较是负数比正数大。
这里对有符号类型处理的方式是将符号位反转,这样正数就比负数大了,
关键代码段如下
Field_long::make_sort_key: if (!table->s->db_low_byte_first) { if (unsigned_flag) to[0] = ptr[0]; else to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */ to[1] = ptr[1]; to[2] = ptr[2]; to[3] = ptr[3]; }
- 字符型
char类型直接补空格
varchar类型为了节省空间处理起来就复杂多了
以源码中的注释为例
const int VARCHAR_CMP_LESS_THAN_SPACES = 1; const int VARCHAR_CMP_EQUAL_TO_SPACES = 2; const int VARCHAR_CMP_GREATER_THAN_SPACES = 3; Example: if fpi->m_segment_size=5, and the collation is latin1_bin: 'abcd ' => [ 'abcd' <VARCHAR_CMP_LESS> ]['