在新建Hive表時,可使用stored as rcfile來指定hive文件的存儲方式爲RCFile。算法
下圖是一個RCFile的文件結構形式。
從上圖能夠看出:
1)一張表能夠包含多個HDFS block。
2)在每一個block中,RCFile以行組(row group,相似於ORC中的stripe)爲單位存儲其中的數據。所謂行組是指在關係型數據塊中,若干條記錄組成的一個group。對於一張表來講,row group的大小是固定的。經過HDFS的block大小和row group的大小,可以肯定一個block上能夠容納多少個row group。
3)row group又由三個部分組成,包括一個用於在block中分隔兩個row group的16字節的標誌區,一個存儲row group元數據信息的header,以及實際數據區。表中的實際數據以列爲單位進行存儲。sql
在存儲RCFile時,會對每一個row group的metadata header區和data區進行壓縮。
在metadata header區中,記錄了該row group中有多少記錄,每一個column總共有多少字節數,以及每一個column中每個field的字節數等信息。對metadata header區,使用RLE(Run Length Encoding)算法來壓縮數據。須要讀取指定column的記錄時,能夠根據這個metadata中記錄的字節數等信息,很快定位到對應的數據。
對data區的數據壓縮時,RCFile文件格式並不會將整個區域一塊兒進行壓縮,而是以列爲單位進行Gzip壓縮,這樣的處理方式使得須要讀取某些指定列的數據時,其餘無關的列不須要進行讀取。
markdown
因爲目前HDFS只支持在文件末尾追加內容,沒法隨意修改hdfs文件中的數據。因此在使用RCFile文件的hive表中也只能在文件末尾寫入新的記錄。在向RCFile寫入數據時,
(1)爲了不頻繁的寫入操做,RCFile會爲每個column在內存中維持一個對應的column holder。當有記錄插入到hive表中時,會把這一條記錄的每一個字段拆散存入到對應的column holder的末尾。伴隨着這個操做的同時,會在metadata header中記錄這次操做的相關信息。
(2)上面的column holder固然是不能無限大的,爲此RCFile設定了兩個參數,當知足任何一個時,就會把column holder中的數據flush到磁盤上。這兩個參數一個是寫入記錄數,另外一個是column holder使用的內存大小。
(3)記錄寫入完畢後,RCFile首先會將metadata header進行壓縮。而後把每個column單獨進行壓縮,最後將壓縮好的數據flush到同一個row group中。性能
當須要從一個row group讀取數據時,RCFile並不會將整個row group中的數據都讀入到內存中,須要讀入的數據只包括metadata header,以及在語句中指定的那些column。
這兩部分數據讀入到內存中後,首先會將metadata header進行解壓縮,並一直保存在內存中。接下來對加載到內存中的column數據,在RCFile中有一個lazy decompression的概念,這個的意思是說,column數據並不會在加載到內存中後立刻進行解壓縮,而是後續處理中的確須要讀取這個column數據時解壓縮過程纔會執行。好比有一個sql語句,select a,b,c from table where a > 5;
首先會對字段a解壓縮,若是判斷全部記錄中沒有a > 5的記錄,那麼字段b和字段c都沒必要要進行解壓縮了。
code
參數 | 默認值 | 描述 |
---|---|---|
hive.io.rcfile.record.buffer.size | 4194304 | 設置row group的大小 |
hive.io.rcfile.record.interval | 2147483647 | row group中最大記錄數 |
row group默認大小爲4MB主要是由於row group不能太大,也不能過小。在Gzip壓縮算法中,增大row group的大小可以提高壓縮的性能。可是當row group的大小達到某個閾值時,繼續增大row group並不能帶來壓縮性能的提高。而且,以上面的sql語句爲例若是一個row group越大,其中保存的記錄也就越多,這樣該row group中出現a >5的記錄的機率就越大,那麼就越難使用到lazy decompression這一特性帶來的性能提高。而且row group越大,消耗的內存也就越多。
這個大小限制在ORC文件格式中獲得了改善。
ip