日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

java 类的存储结构设计_Doris存储层设计介绍1——存储结构设计解析

發布時間:2023/11/27 生活经验 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 类的存储结构设计_Doris存储层设计介绍1——存储结构设计解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1?整體介紹

Doris是基于MPP架構的交互式SQL數據倉庫,主要用于解決了近實時的報表和多維分析。Doris高效的導入、查詢離不開其存儲結構精巧的設計。本文主要通過閱讀Doris BE模塊代碼,詳細分析了Doris BE模塊存儲層的實現原理,闡述和解密Doris高效的寫入、查詢能力背后的核心技術。其中包括Doris列存的設計、索引設計、數據讀寫流程、Compaction流程、Tablet和Rowset的版本管理、數據備份等功能。這里會通過三篇文章來逐步進行介紹,分別為《Doris存儲層設計介紹1——存儲結構設計解析》、《Doris存儲層設計介紹2——讀寫、compaction流程分析》、《Doris存儲層設計介紹3——Tablet管理、數據備份》。

Doris 微信公眾號:

本文為第一篇《Doris存儲層設計介紹1——存儲結構設計解析》,文章介紹了Segment V2版本的存儲層結構,包括了有序存儲、稀疏索引、前綴索引、位圖索引、BloomFilter等豐富功能,可以應對各種復雜的場景提供極速的查詢能力。

2?設計目標

批量導入,少量更新

絕大多數的讀請求

寬表場景,讀取大量行,少量列

非事務場景

良好的擴展性

3?存儲文件格式

3.1?存儲目錄結構

存儲層對存儲數據的管理通過storage_root_path路徑進行配置,路徑可以是多個。存儲目錄下一層按照分桶進行組織,分桶目錄下存放具體的tablet,按照tablet_id命名子目錄。

Segment文件存放在tablet_id目錄下按SchemaHash管理。Segment文件可以有多個,一般按照大小進行分割,默認為256MB。其中,Segment v2文件命名規則為:${rowset_id}_${segment_id}.dat。具體存儲目錄存放格式如下圖所示:

3.2 Segment v2文件結構

Segment整體的文件格式分為數據區域,索引區域和footer三個部分,如下圖所示:

Data Region:用于存儲各個列的數據信息,這里的數據是按需分page加載的

Index Region: Doris中將各個列的index數據統一存儲在Index Region,這里的數據會按照列粒度進行加載,所以跟列的數據信息分開存儲

Footer信息

SegmentFooterPB:定義文件的元數據信息

4個字節的FooterPB內容的checksum

4個字節的FileFooterPB消息長度,用于讀取FileFooterPB

8個字節的MAGIC CODE,之所以在末位存儲,是方便不同的場景進行文件類型的識別

下面分布介紹各個部分的存儲格式的設計。

4?Footer信息

Footer信息段在文件的尾部,存儲了文件的整體結構,包括數據域的位置,索引域的位置等信息,其中有SegmentFooterPB,CheckSum,Length,MAGIC CODE 4個部分。

SegmentFooterPB數據結構如下:

SegmentFooterPB采用了PB格式進行存儲,主要包含了列的meta信息、索引的meta信息,Segment的short key索引信息、總行數。

4.1 列的meta信息

ColumnId:當前列在schema中的序號

UniqueId:全局唯一的id

Type:列的類型信息

Length:列的長度信息

Encoding:編碼格式

Compression:壓縮格式

Dict PagePointer:字典信息

4.2 列索引的meta信息

OrdinalIndex:存放列的稀疏索引meta信息。

ZoneMapIndex:存放ZoneMap索引的meta信息,內容包括了最大值、最小值、是否有空值、是否沒有非空值。SegmentZoneMap存放了全局的ZoneMap信息,PageZoneMaps則存放了每個頁面的統計信息。

BitMapIndex:存放BitMap索引的meta信息,內容包括了BitMap類型,字典數據BitMap數據。

BloomFilterIndex:存放了BloomFilter索引信息。

為了防止索引本身數據量過大,ZoneMapIndex、BitMapIndex、BloomFilterIndex采用了兩級的Page管理。對應了IndexColumnMeta的結構,當一個Page能夠放下時,當前Page直接存放索引數據,即采用1級結構;當一個Page無法放下時,索引數據寫入新的Page中,Root Page存儲數據Page的地址信息。

5?Ordinal Index(一級索引)

Ordinal Index索引提供了通過行號來查找Column Data Page數據頁的物理地址。Ordinal Index能夠將按列存儲數據按行對齊,可以理解為一級索引。其他索引查找數據時,都要通過Ordinal Index查找數據Page的位置。因此,這里先介紹Ordinal Index索引。

在一個segment中,數據始終按照key(AGGREGATE KEY、UNIQ KEY 和 DUPLICATE KEY)排序順序進行存儲,即key的排序決定了數據存儲的物理結構。確定了列數據的物理結構順序,在寫入數據時,Column Data Page是由Ordinal index進行管理,Ordinal index記錄了每個Column Data Page的位置offset、大小size和第一個數據項行號信息,即Ordinal。這樣每個列具有按行信息進行快速掃描的能力。Ordinal index采用的稀疏索引結構,就像是一本書目錄,記錄了每個章節對應的頁碼。

5.1 存儲結構

Ordinal index元信息存儲在SegmentFooterPB中的每個列的OrdinalIndexMeta中。具體結構如下圖所示:

在OrdinalIndexMeta中存放了索引數據對應的root page地址,這里做了一些優化,當數據僅有一個page時,這里的地址可以直接指向唯一的數據page;當一個page放不下時,指向OrdinalIndex類型的二級結構索引page,索引數據中每個數據項對應了Column Data Page offset位置、size大小和ordinal行號信息。其中Ordinal index索引粒度與page粒度一致,默認64*1024字節。

6、列數據存儲

Column的data數據按照Page為單位分塊存儲,每個Page大小一般為64*1024個字節。Page在存儲的位置和大小由ordinal index管理。

6.1 data page存儲結構

DataPage主要為Data部分、Page Footer兩個部分。

Data部分存放了當前Page的列的數據。當允許存在Null值時,對空值單獨存放了Null值的Bitmap,由RLE格式編碼通過bool類型記錄Null值的行號。

Page Footer包含了Page類型Type、UncompressedSize未壓縮時的數據大小、FirstOrdinal當前Page第一行的RowId、NumValues為當前Page的行數、NullMapSize對應了NullBitmap的大小。

6.2 數據壓縮

針對不同的字段類型采用了不同的編碼。默認情況下,針對不同類型采用的對應關系如下:

TINYINT/SMALLINT/INT/BIGINT/LARGEINT

BIT_SHUFFLE

FLOAT/DOUBLE/DECIMAL

BIT_SHUFFLE

CHAR/VARCHAR

DICT

BOOL

RLE

DATE/DATETIME

BIT_SHUFFLE

HLL/OBJECT

PLAIN

默認采用LZ4F格式對數據進行壓縮。

7、Short Key Index索引

7.1 存儲結構

Short Key Index前綴索引,是在key(AGGREGATE KEY、UNIQ KEY 和 DUPLICATE KEY)排序的基礎上,實現的一種根據給定前綴列,快速查詢數據的索引方式。這里Short Key Index索引也采用了稀疏索引結構,在數據寫入過程中,每隔一定行數,會生成一個索引項。這個行數為索引粒度默認為1024行,可配置。該過程如下圖所示:

其中,KeyBytes中存放了索引項數據,OffsetBytes存放了索引項在KeyBytes中的偏移。

7.2 索引生成規則

Short Key Index采用了前36 個字節,作為這行數據的前綴索引。當遇到 VARCHAR 類型時,前綴索引會直接截斷。

7.3 應用案例

(1)以下表結構的前綴索引為 user_id(8Byte) + age(4Bytes) + message(prefix 24 Bytes)。

ColumnName

Type

user_id

BIGINT

age

INT

message

VARCHAR(100)

max_dwell_time

DATETIME

min_dwell_time

DATATIME

(2)以下表結構的前綴索引為 user_name(20 Bytes)。即使沒有達到 36 個字節,因為遇到 VARCHAR,所以直接截斷,不再往后繼續。

Column

Type

user_name

VARCHAR(20)

age

INT

message

VARCHAR(100)

max_dwell_time

DATETIME

min_dwell_time

DATETIME

當我們的查詢條件,是前綴索引的前綴時,可以極大的加快查詢速度。比如在第一個例子中,我們執行如下查詢:

SELECT * FROM table WHERE user_id=1829239 and age=20;

該查詢的效率會遠高于如下查詢:

SELECT * FROM table WHERE age=20;

所以在建表時,正確的選擇列順序,能夠極大地提高查詢效率。

8、ZoneMap Index索引

ZoneMap索引存儲了Segment和每個列對應每個Page的統計信息。這些統計信息可以幫助在查詢時提速,減少掃描數據量,統計信息包括了Min最大值、Max最小值、HashNull空值、HasNotNull不全為空的信息。

8.1 存儲結構

ZoneMap索引存儲結構如下圖所示:

在SegmentFootPB結構中,每一列索引元數據ColumnIndexMeta中存放了當前列的ZoneMapIndex索引數據信息。ZoneMapIndex有兩個部分,SegmentZoneMap和PageZoneMaps。SegmentZoneMap存放了當前Segment全局的ZoneMap索引信息,PageZoneMaps存放了每個Data Page的ZoneMap索引信息。

PageZoneMaps對應了索引數據存放的Page信息IndexedColumnMeta結構,目前實現上沒有進行壓縮,編碼方式也為Plain。IndexedColumnMeta中的OrdinalIndexPage指向索引數據root page的偏移和大小,這里同樣做了優化二級Page優化,當僅有一個DataPage時,OrdinalIndexMeta直接指向這個DataPage;有多個DataPage時,OrdinalIndexMeta先指向OrdinalIndexPage,OrdinalIndexPage是一個二級Page結構,里面的數據項為索引數據DataPage的地址偏移offset,大小Size和ordinal信息。

8.2 索引生成規則

Doris默認為key列開啟ZoneMap索引;當表的模型為DUPULCATE時,會所有字段開啟ZoneMap索引。在列數據寫入Page時,自動對數據進行比較,不斷維護當前Segment的ZoneMap和當前Page的ZoneMap索引信息。

8.3 應用案例

在數據查詢時,會根據范圍條件過濾的字段會按照ZoneMap統計信息選取掃描的數據范圍。例如在案例1中,對age字段進行過濾。查詢語句如下:

SELECT * FROM table WHERE age > 20 and age < 1000

在沒有命中Short Key Index的情況下,會根據條件語句中age的查詢條件,利用ZoneMap索引找到應該掃描的數據ordinary范圍,減少要掃描的page數量。

9、BloomFilter

當一些字段不能利用Short Key Index并且字段存在區分度比較大時,Doris提供了BloomFilter索引。

9.1、存儲結構

BloomFilter的存儲結構如下圖所示:

BloomFilterIndex信息存放了生產的Hash策略、Hash算法和BloomFilter過對應的數據Page信息。Hash算法采用了HASH_MURMUR3,Hash策略采用了BlockSplitBloomFilter分塊實現策略,期望的誤判率fpp默認配置為0.05。BloomFilter索引數據對應數據Page的存放與ZoneMapIndex類似,做了二級Page的優化,這里不再詳細闡述。

9.2、索引生成規則

BloomFilter按Page粒度生成,在數據寫入一個完整的Page時,Doris會根據Hash策略同時生成這個Page的BloomFilter索引數據。目前bloom過濾器不支持tinyint/hll/float/double類型,其他類型均已支持。使用時需要在PROPERTIES中指定bloom_filter_columns要使用BloomFilter索引的字段。

9.3 應用案例

在數據查詢時,查詢條件在設置有bloom過濾器的字段進行過濾,當bloom過濾器沒有命中時表示該Page中沒有該數據,這樣可以減少要掃描的page數量。

案例:table的schema如下:

ColumnName

Type

user_id

BIGINT

age

INT

name

VARCHAR(20)

city

VARCHAR(200)

createtime

DATETIME

這里的查詢sql如下:

SELECT * FROM table WHERE name = '張三'

由于name的區分度較大,為了提升sql的查詢性能,對name數據增加了BloomFilter索引,PROPERTIES ( "bloom_filter_columns" = "name" )。在查詢時通過BloomFilter索引能夠大量過濾掉Page。

10、Bitmap Index索引

Doris還提供了BitmapIndex用來加速數據的查詢。

10.1、存儲結構

Bitmap存儲格式如下:

BitmapIndex的meta信息同樣存放在SegmentFootPB中,BitmapIndex包含了三部分,BitMap的類型、字典信息DictColumn、位圖索引數據信息BitMapColumn。其中DictColumn、BitMapColumn都對應IndexedColumnData結構,分別存放了字典數據和索引數據的Page地址offset、大小size。這里同樣做了二級page的優化,不再具體闡述。

這里與其他索引存儲結構有差異的地方是DictColumn字典數據進行了LZ4F壓縮,在記錄二級Page偏移時存放的是Data Page中的第一個值。

10.2、索引生成規則

BitMap創建時需要通過 CREATE INDEX 進行創建。Bitmap的索引是整個Segment中的Column字段的索引,而不是為每個Page單獨生成一份。在寫入數據時,會維護一個map結構記錄下每個key值對應的行號,并采用Roaring位圖對rowid進行編碼。主要結構如下:

生成索引數據時,首先寫入字典數據,將map結構的key值寫入到DictColumn中。然后,key對應Roaring編碼的rowid以字節方式將數據寫入到BitMapColumn中。

10.3、應用案例

在數據查詢時,對于區分度不大,列的基數比較小的數據列,可以采用位圖索引進行優化。比如,性別,婚姻,地理信息等。

案例:table的schema如下:

ColumnName

Type

user_id

BIGINT

age

INT

name

VARCHAR(20)

city

VARCHAR(200)

createtime

DATETIME

這里的查詢sql如下:

SELECT * FROM table WHERE city in ("北京", "上海")

由于city的取值比較少,建立數據字典和位圖后,通過掃描位圖便可以快速查找出匹配行。并且位圖壓縮后,數據量本身較小,通過掃描較少數據變能夠對整個列進行精確的匹配。

11、索引的查詢流程

在查詢一個Segment中的數據時,根據執行的查詢條件,會對首先根據字段加索引的情況對數據進行過濾。然后在進行讀取數據,整體的查詢流程如下:

首先,會按照Segment的行數構建一個row_bitmap,表示記錄那些數據需要進行讀取,沒有使用任何索引的情況下,需要讀取所有數據。

當查詢條件中按前綴索引規則使用到了key時,會先進行ShortKey Index的過濾,可以在ShortKey Index中匹配到的ordinal行號范圍,合入到row_bitmap中。

當查詢條件中列字段存在BitMap Index索引時,會按照BitMap索引直接查出符合條件的ordinal行號,與row_bitmap求交過濾。這里的過濾是精確的,之后去掉該查詢條件,這個字段就不會再進行后面索引的過濾。

當查詢條件中列字段存在BloomFilter索引并且條件為等值(eq,in,is)時,會按BloomFilter索引過濾,這里會走完所有索引,過濾每一個Page的BloomFilter,找出查詢條件能命中的所有Page。將索引信息中的ordinal行號范圍與row_bitmap求交過濾。

當查詢條件中列字段存在ZoneMap索引時,會按ZoneMap索引過濾,這里同樣會走完所有索引,找出查詢條件能與ZoneMap有交集的所有Page。將索引信息中的ordinal行號范圍與row_bitmap求交過濾。

生成好row_bitmap之后,批量通過每個Column的OrdinalIndex找到到具體的Data Page。

批量讀取每一列的Column Data Page的數據。在讀取時,對于有null值的page,根據null值位圖判斷當前行是否是null,如果為null進行直接填充即可。

12、總結

Doris目前采用了完全的列存儲結構,并提供了豐富的索引應對不同查詢場景,為Doris高效的寫入、查詢性能奠定了夯實的基礎。Doris存儲層設計靈活,未來還可以進一步增加新的索引、強化數據刪除等功能。

總結

以上是生活随笔為你收集整理的java 类的存储结构设计_Doris存储层设计介绍1——存储结构设计解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。