上一章聊到 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是如何執行的呢,是怎樣進行的查詢?又是怎樣高速的寫入數據?
歡迎持續關注。。。。