时序数据库 Apache-IoTDB 源码解析之元数据索引块(六)

时序数据库 Apache-IoTDB 源码解析之元数据索引块(六)

上一章聊到 TsFile 索引块的详细介绍,以及一个查询所经过的步骤。详情请见:

时序数据库 Apache-IoTDB 源码解析之文件索引块(五)

打一波广告,欢迎大家访问 IoTDB 仓库,求一波 Star 。欢迎关注头条号:列炮缓开局,欢迎关注OSCHINA博客

阿里云、东方国信等各家公司正在招聘IoTDB数据库开发工程师,欢迎加我微信内推:liutaohua001

这一章主要想聊聊:

  1. 原有索引中的不足
  2. 新版本中索引的设计

原有索引中的不足

现在来张图回顾一下原有的数据存储方式,在文件尾部使用DeviceMetaDataIndexMap和MeasurementSchemaMap中记录所有设备数据偏移量、传感器的相关信息等。因为使用的是Map结构访问都是O(1)的,但是需要关注的一个问题就是它是在内存中O(1)的,在磁盘上并不能找到什么好的查询方式,唯一能做的就是全部读取出来然后放到内存中。

通常情况下这不会有什么问题,但是使用在工业场景中,传感器+设备很有可能数以百万计,这会引发无论你读取的是一个传感器或者是一个设备的数据,在DeviceMetaDataIndexMap这一段数据都需要完整的从磁盘上读取回来,这好吗?这不好,还拿之前的数据举例:

时间戳人名体温年龄
1580950800张一36.530
1580950800张二36.930
1580950800张三36.730
1580950800张…36.730
1580950800张两百万36.730

当执行一个查询select 体温 from 张三 where time = 1580950800 时,张一、张二、张三…张两百万这两百万个名字都需要从硬盘中读取并反序列化出来(通常 IoTDB 中的路径是root.T000100010002.A_JB01.JB01.JTJBGMCA6K2052561),也就是1999999个都是多余的读取。

此外,在TsDeviceMetaDataList中,也是按照chunkGroup存储,意味着,如果我仅查询一列,同样会把其它的列信息读取出来。

新版本中索引的设计

为了尽可能贴近只读投影列的思想,新版本中对于TsDeviceMetaDataList部分不再按照设备级别存储,改为按照传感器级别存储,TsFileMetaData部分不再使用map存储所有设备,改为使用多叉树并有序排列

改动1: 使用将一个传感器的所有ChunkMetaData的存储在一起,并使用TimeseriesMetadata结构进行维护(保存某个传感器的开始的offset及数据长度),如图:

改动2: 在完成改动1之后,我们得到了TimeSeriesMetadata-年龄,TimeSeriesMetadata-体温, ..., TimeSeriesMetadata-x,在刷盘之前将所有TimeSeriesMetadata按照传感器名字排序,那么在这里就可以进行二分查找了,如图:

改动3: 在一个复杂的设备上传感器很有可能多达数千个,例如:新能源汽车当中,每台车量可以多达4000多个信号项。假如我们需要管理10万辆车,那么依然会有10万 * 4000 = 4亿个TimeSeriesMetadata。还是太多了,假如我们进行多个传感器的值查询时,每次都进行二分,这无疑是浪费的。

所以进行一个树状的提取,假设每1024个提取一次,那么4亿个可以节省为390,625个,假如再抽取一次,那就可以减少到382个了,这样我们从硬盘上一次读取1024个,最多读取3次硬盘就可以完成查找。大意如图:

改动4: 除了传感器之外,还要考虑的是设备级别,因为设备也是数以万计,但同上面的逻辑是一样的。再此就不进行赘述,如图:

在代码中使用MetadataIndexNode类进行存储图中的数据,代表了当前节点属于管理设备的节点还是管理传感器的节点,是中间节点还是叶子节点。使用MetadataIndexEntry用来存储具体的信息,也就是TimeSeriesMetadata结构在硬盘上的偏移量或者子节点MetadataIndexNode在硬盘上的偏移量.

附上一个文件展示:


            POSITION|	CONTENT
            -------- 	-------
                   0|	[magic head] TsFile
                   6|	[version number] 000002
|||||||||||||||||||||	[Chunk Group] of root.sg1.d1, num of Chunks:10000
                  12|	[Chunk] of s8289, numOfPoints:500, time range:[0,499], tsDataType:INT64, 
                     	startTime: 0 endTime: 499 count: 500 [minValue:1,maxValue:1,firstValue:1,lastValue:1,sumValue:500.0]
                    |		1 pages
                    		 ...
              350026|	[Chunk] of s0, numOfPoints:500, time range:[0,499], tsDataType:INT64, 
                     	startTime: 0 endTime: 499 count: 500 [minValue:1,maxValue:1,firstValue:1,lastValue:1,sumValue:500.0]
                    |		1 pages
                    		 ...
             1418902|	[Chunk Group Footer]
                    |		[marker] 0
                    |		[deviceID] root.sg1.d1
                    |		[dataSize] 1418890
                    |		[num of chunks] 10000
|||||||||||||||||||||	[Chunk Group] of root.sg1.d1 ends
             1418947|	[marker] 2
             1418948|	[ChunkMetadataList] of root.sg1.d1.s0, tsDataType:INT64
                    |		 [ChunkMetaData] of s0, offset:350026
                    		 ...
             2247838|	[TimeseriesMetadata] name:s0, offset:1418948, chunkMetaDataListDataSize:80
             3116728|	[MetadataIndexNode] nodeType:LEAF_MEASUREMENT, childSize:10
                    |		[MetadataIndexEntry] name:s0, offset:2247838, endOffset:2336808
                    |		[MetadataIndexEntry] name:s192, offset:2336808, endOffset:2425782
                    |		[MetadataIndexEntry] name:s2841, offset:2425782, endOffset:2514757
                    |		[MetadataIndexEntry] name:s3763, offset:2514757, endOffset:2603732
                    |		[MetadataIndexEntry] name:s4685, offset:2603732, endOffset:2692705
                    |		[MetadataIndexEntry] name:s5606, offset:2692705, endOffset:2781680
                    |		[MetadataIndexEntry] name:s6528, offset:2781680, endOffset:2870655
                    |		[MetadataIndexEntry] name:s745, offset:2870655, endOffset:2959629
                    |		[MetadataIndexEntry] name:s8371, offset:2959629, endOffset:3048604
                    |		[MetadataIndexEntry] name:s9293, offset:3048604, endOffset:3116728
             3116906|	[TsFileMetadata] deviceNums:1,chunkNums:10000,invalidChunkNums:0
                    |		[MetadataIndexNode] nodeType:INTERNAL_MEASUREMENT,childSize:1
                    |			[MetadataIndexEntry] name:root.sg1.d1,offset:3116728,endOffset:3116906
                    |		[bloom filter bit vector byte array length] 7794
                    |		[bloom filter bit vector byte array] 
                    |		[bloom filter number of bits] 62353
                    |		[bloom filter number of hash functions] 5
             3124764|	[TsFileMetadataSize] 7858
             3124768|	[magic tail] TsFile
             3124774|	END of TsFile

---------------------------------- TsFile Sketch End ----------------------------------

到此已经介绍完了文件的整体结构,以及索引的改进过程。

那么一个sql是如何执行的呢,是怎样进行的查询?又是怎样高速的写入数据?

欢迎持续关注。。。。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值