比如查询一行数据,该数据在第几块第几行,即该行的物理位置,类似postgresql里的ctid;
如果可以的话应该就能统计出当前一个块有多少行数据
没有办法查到和pg这样的查询 这个和ob设计有关
OB4.0采用单日志流架构来解决这些问题。类似的,OB之前的架构设计也没有考虑机器资源比较少时,尤其是内存资源比较少时,如何支持很多分区以及如何支持很多数据。
OB之前的版本每创建一个分区,都会创建ObPGPartition
(表示一个分区的对象)、ObPartitionStorage
(表示分区存储相关操作接口的对象)、ObPartitionStore
(表示分区主表索引表的管理结构)、ObMultiVersionTableStore
(与后面的ObTableStore
一起表示分区MemTable和SSTable的管理结构)、ObTableStore
等一系列数据结构,占用的内存接近200KB,一个内存几GB的机器,单纯从内存来看,也建不了几万个分区。
同时,用户写入的数据经过转储和合并后以SSTable结构存储在硬盘上,SSTable内部是由2MB大小的宏块来存储数据,每个宏块在硬盘上对应了2MB的数据,在内存中需要一个元数据结构ObMacroBlockMeta
,保存了宏块的行数、列数、schema版本等基本信息,其中还要包括一个endkey
结构,保存了宏块最后一行数据的主键内容。SSTable内的宏块都是有序存储的,利用内存中缓存的endkey
可以检索到一行数据所在宏块。这样的一个元数据结构必须常驻内存,根据endkey
实际内容不同,需要占用不同大小的内存,平均在2KB左右。这就是说,硬盘上每有2MB数据,内存中就会占用2KB内存。一个内存几GB的机器,即使内存全用来存宏块元数据,也装不了几TB的数据。
分区个数的限制和数据量大小的限制都是制约小规格机器功能的基础问题。
OB4.0中会把需要常驻内存的信息进行极致精简,实际的信息都是持久化在硬盘上,根据使用的需求按需加载。原先的宏块元数据都在内存中,宏块的数据在硬盘上,这可以看作是一个两层结构,第一层是宏块数据,第二层是元数据。 新的方案中,当宏块很多时,若干个连续宏块的元数据会聚集在一起形成一个数据块,这种元数据组成的数据块会持久化在硬盘中,并且会有一个针对这种持久化数据块的元数据,即元数据的元数据,可以看作第三层。第三层数据还可能很多,这些元数据会再次聚集并持久化。以此类推,直到顶层只有一个数据块。而这样的数据组织方式实际组成了一个树状结构,叶子节点是宏块,中间层都是元数据和元数据的元数据。这些中间层也能持久化,并在查找时按需加载到缓存中使用。如此,无论存储多少数据量,元数据都不会再占用内存了。
分区的一系列管理数据结构也会用将原本常驻内存的结构转换成数据持久化到硬盘上,比如管理MemTable和SSTable结构的ObTableStore
会把映射关系持久化到硬盘中,只在内存中留下持久化的位置,如果分区不被访问,那么就不需要加载ObTableStore
对应的数据,当分区被访问时再按需加载。
经过上面所述方法的处理,每个分区在内存中占用的内存量会缩减到100~200字节,并且跟分区的数据量无关,那么小规格机器对分区数量和存储的数据量也就几乎没有限制了。