上一章聊到 TsFile 索引块的详细介绍,以及一个查询所通过的步骤。详情请见:node
时序数据库 Apache-IoTDB 源码解析之文件索引块(五)git
打一波广告,欢迎你们访问 IoTDB 仓库,求一波 Star 。欢迎关注头条号:列炮缓开局,欢迎关注OSCHINA博客github
阿里云、东方国信等各家公司正在招聘IoTDB数据库开发工程师,欢迎加我微信内推:liutaohua001
sql
这一章主要想聊聊:数据库
- 原有索引中的不足
- 新版本中索引的设计
原有索引中的不足
如今来张图回顾一下原有的数据存储方式,在文件尾部使用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是如何执行的呢,是怎样进行的查询?又是怎样高速的写入数据?
欢迎持续关注。。。。