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

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

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

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

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

这一章主要想聊聊:数据库

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

原有索引中的不足

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

一般状况下这不会有什么问题,可是使用在工业场景中,传感器+设备颇有可能数以百万计,这会引起不管你读取的是一个传感器或者是一个设备的数据,在DeviceMetaDataIndexMap这一段数据都须要完整的从磁盘上读取回来,这好吗?这很差,还拿以前的数据举例:微信

时间戳 人名 体温 ... 年龄
1580950800 张一 36.5 ... 30
1580950800 张二 36.9 ... 30
1580950800 张三 36.7 ... 30
1580950800 张.. 36.7 ... 30
1580950800 张两百万 36.7 ... 30

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

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

新版本中索引的设计

为了尽量贴近只读投影列的思想,新版本中对于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是如何执行的呢,是怎样进行的查询?又是怎样高速的写入数据?

欢迎持续关注。。。。

相关文章
相关标签/搜索