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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

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

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

1?整體介紹

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

Doris 微信公眾號:

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

2?設(shè)計目標(biāo)

批量導(dǎo)入,少量更新

絕大多數(shù)的讀請求

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

非事務(wù)場景

良好的擴展性

3?存儲文件格式

3.1?存儲目錄結(jié)構(gòu)

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

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

3.2 Segment v2文件結(jié)構(gòu)

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

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

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

Footer信息

SegmentFooterPB:定義文件的元數(shù)據(jù)信息

4個字節(jié)的FooterPB內(nèi)容的checksum

4個字節(jié)的FileFooterPB消息長度,用于讀取FileFooterPB

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

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

4?Footer信息

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

SegmentFooterPB數(shù)據(jù)結(jié)構(gòu)如下:

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

4.1 列的meta信息

ColumnId:當(dāng)前列在schema中的序號

UniqueId:全局唯一的id

Type:列的類型信息

Length:列的長度信息

Encoding:編碼格式

Compression:壓縮格式

Dict PagePointer:字典信息

4.2 列索引的meta信息

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

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

BitMapIndex:存放BitMap索引的meta信息,內(nèi)容包括了BitMap類型,字典數(shù)據(jù)BitMap數(shù)據(jù)。

BloomFilterIndex:存放了BloomFilter索引信息。

為了防止索引本身數(shù)據(jù)量過大,ZoneMapIndex、BitMapIndex、BloomFilterIndex采用了兩級的Page管理。對應(yīng)了IndexColumnMeta的結(jié)構(gòu),當(dāng)一個Page能夠放下時,當(dāng)前Page直接存放索引數(shù)據(jù),即采用1級結(jié)構(gòu);當(dāng)一個Page無法放下時,索引數(shù)據(jù)寫入新的Page中,Root Page存儲數(shù)據(jù)Page的地址信息。

5?Ordinal Index(一級索引)

Ordinal Index索引提供了通過行號來查找Column Data Page數(shù)據(jù)頁的物理地址。Ordinal Index能夠?qū)戳写鎯?shù)據(jù)按行對齊,可以理解為一級索引。其他索引查找數(shù)據(jù)時,都要通過Ordinal Index查找數(shù)據(jù)Page的位置。因此,這里先介紹Ordinal Index索引。

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

5.1 存儲結(jié)構(gòu)

Ordinal index元信息存儲在SegmentFooterPB中的每個列的OrdinalIndexMeta中。具體結(jié)構(gòu)如下圖所示:

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

6、列數(shù)據(jù)存儲

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

6.1 data page存儲結(jié)構(gòu)

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

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

Page Footer包含了Page類型Type、UncompressedSize未壓縮時的數(shù)據(jù)大小、FirstOrdinal當(dāng)前Page第一行的RowId、NumValues為當(dāng)前Page的行數(shù)、NullMapSize對應(yīng)了NullBitmap的大小。

6.2 數(shù)據(jù)壓縮

針對不同的字段類型采用了不同的編碼。默認情況下,針對不同類型采用的對應(yīng)關(guān)系如下:

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格式對數(shù)據(jù)進行壓縮。

7、Short Key Index索引

7.1 存儲結(jié)構(gòu)

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

其中,KeyBytes中存放了索引項數(shù)據(jù),OffsetBytes存放了索引項在KeyBytes中的偏移。

7.2 索引生成規(guī)則

Short Key Index采用了前36 個字節(jié),作為這行數(shù)據(jù)的前綴索引。當(dāng)遇到 VARCHAR 類型時,前綴索引會直接截斷。

7.3 應(yīng)用案例

(1)以下表結(jié)構(gòu)的前綴索引為 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)以下表結(jié)構(gòu)的前綴索引為 user_name(20 Bytes)。即使沒有達到 36 個字節(jié),因為遇到 VARCHAR,所以直接截斷,不再往后繼續(xù)。

Column

Type

user_name

VARCHAR(20)

age

INT

message

VARCHAR(100)

max_dwell_time

DATETIME

min_dwell_time

DATETIME

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

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

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

SELECT * FROM table WHERE age=20;

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

8、ZoneMap Index索引

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

8.1 存儲結(jié)構(gòu)

ZoneMap索引存儲結(jié)構(gòu)如下圖所示:

在SegmentFootPB結(jié)構(gòu)中,每一列索引元數(shù)據(jù)ColumnIndexMeta中存放了當(dāng)前列的ZoneMapIndex索引數(shù)據(jù)信息。ZoneMapIndex有兩個部分,SegmentZoneMap和PageZoneMaps。SegmentZoneMap存放了當(dāng)前Segment全局的ZoneMap索引信息,PageZoneMaps存放了每個Data Page的ZoneMap索引信息。

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

8.2 索引生成規(guī)則

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

8.3 應(yīng)用案例

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

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

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

9、BloomFilter

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

9.1、存儲結(jié)構(gòu)

BloomFilter的存儲結(jié)構(gòu)如下圖所示:

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

9.2、索引生成規(guī)則

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

9.3 應(yīng)用案例

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

案例:table的schema如下:

ColumnName

Type

user_id

BIGINT

age

INT

name

VARCHAR(20)

city

VARCHAR(200)

createtime

DATETIME

這里的查詢sql如下:

SELECT * FROM table WHERE name = '張三'

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

10、Bitmap Index索引

Doris還提供了BitmapIndex用來加速數(shù)據(jù)的查詢。

10.1、存儲結(jié)構(gòu)

Bitmap存儲格式如下:

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

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

10.2、索引生成規(guī)則

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

生成索引數(shù)據(jù)時,首先寫入字典數(shù)據(jù),將map結(jié)構(gòu)的key值寫入到DictColumn中。然后,key對應(yīng)Roaring編碼的rowid以字節(jié)方式將數(shù)據(jù)寫入到BitMapColumn中。

10.3、應(yīng)用案例

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

案例: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的取值比較少,建立數(shù)據(jù)字典和位圖后,通過掃描位圖便可以快速查找出匹配行。并且位圖壓縮后,數(shù)據(jù)量本身較小,通過掃描較少數(shù)據(jù)變能夠?qū)φ麄€列進行精確的匹配。

11、索引的查詢流程

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

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

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

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

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

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

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

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

12、總結(jié)

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。