以前據說 RCFile 在讀取數據時能夠跳過不須要的列,不須要將一整行讀入而後選擇所需字段,因此在 Hive 中執行 select a, b from tableA where c = 1
這樣的操做就相對比較高效。爲了知足好奇心,找了一下關於 RCFile 的論文(RCFile: A Fast and Space-efficient Data Placement Structure in MapReduce-based Warehouse System)看了一下,這裏記錄一下看成筆記。html
首先大數據的查詢和處理有如下幾個需求:數據庫
在傳統的數據庫系統中,主要有三種數據存儲方式:緩存
水平的行存儲結構: 行存儲模式就是把一整行存在一塊兒,包含全部的列,這是最多見的模式。這種結構能很好的適應動態的查詢,好比 select a from tableA
和 select a, b, c, d, e, f, g from tableA
這樣兩個查詢其實查詢的開銷差很少,都須要把全部的行讀進來過一遍,拿出須要的列。並且這種狀況下,屬於同一行的數據都在同一個 HDFS 塊上,重建一行數據的成本比較低。可是這樣作有兩個主要的弱點:a)當一行中有不少列,而咱們只須要其中不多的幾列時,咱們也不得不把一行中全部的列讀進來,而後從中取出一些列。這樣大大下降了查詢執行的效率。b)基於多個列作壓縮時,因爲不一樣的列數據類型和取值範圍不一樣,壓縮比不會過高。網絡
垂直的列存儲結構: 列存儲是將每列單獨存儲或者將某幾個列做爲列組存在一塊兒。列存儲在執行查詢時能夠避免讀取沒必要要的列。並且通常同列的數據類型一致,取值範圍相對多列混合更小,在這種狀況下壓縮數據能達到比較高的壓縮比。可是這種結構在重建出行時比較費勁,尤爲適當一行的多個列不在一個 HDFS 塊上的時候。 好比咱們從第一個 DataNode 上拿到 column A,從第二個 DataNode 上拿到了 column B,又從第三個 DataNode 上拿到了 column C,當要把 A,B,C 拼成一行時,就須要把這三個列放到一塊兒重建出行,須要比較大的網絡開銷和運算開銷。佈局
混合的 PAX 存儲結構: PAX 結構是將行存儲和列存儲混合使用的一種結構,主要是傳統數據庫中提升 CPU 緩存利用率的一種方法,並不能直接用到 HDFS 中。可是 RCFile 也是繼承自它的思想,先按行存再按列存。post
<!--more-->大數據
數據的佈局: 首先根據 HDFS 的結構,一個表能夠由多個 HDFS 塊構成。在每一個 HDFS 塊中,RCFile 以 row group 爲基本單位組織數據,一個表多全部 row group 大小一致,一個 HDFS 塊中能夠包含多個 row group。每一個 row group 包含三個部分,第一部分是 sync marker,用來區分一個 HDFS 塊中兩個連續多 row group。第二部分是 row group 的 metadata header,記錄每一個 row group 中有多少行數據,每一個列數據有多少字節,以及每列一行數據的字節數。第三部分就是 row group 中的實際數據,這裏是按列存儲的。優化
數據的壓縮: 在 metadata header 部分用 RLE (Run Length Encoding) 方法壓縮,由於對於記錄每一個列數據中一行數據的字節數是同樣的,這些數字重複連續出現,所以用這種方法壓縮比比較高。在壓縮實際數據時,每列單獨壓縮。編碼
數據的追加寫: RCFile 會在內存裏維護每一個列的數據,叫 column holder,當一條記錄加入時,首先會被打散成多個列,人後追加到每列對應的 column holder,同時更新 metadata header 部分。能夠經過記錄數或者緩衝區大小控制內存中 column holder 的大小。當記錄數或緩衝大小超過限制,就會先壓縮 metadata header,再壓縮 column holder,而後寫到 HDFS。設計
數據的讀取和惰性解壓(lazy decompression): RCFile 在處理一個 row group 時,只會讀取 metadata header 和須要的列,合理利用列存儲在 I/O 方面的優點。並且即便在查詢中出現的列技術讀進內存也不必定會被解壓縮,只有但肯定該列數據須要用時纔會去解壓,也就是惰性解壓(lazy decompression)。例如對於 select a from tableA where b = 1
,會先解壓 b 列,若是對於整個 row group 中的 b 列,值都不爲 1,那麼就不必對這個 row group 對 a 列去解壓,由於整個 row group 都跳過了。
row group 的大小: row group 過小確定是不能充分發揮列存儲的優點,可是太大也會有問題。首先,論文中實驗指出,當 row group 超過某一閾值時,很難再得到更高當壓縮比。其次,row group 太大會下降 lazy decompression 帶來的益處,仍是拿 select a from tableA where b = 1
來講,若是一個 row group 裏有一行 b = 1
,咱們仍是要解壓 a 列,從而根據 metadata header 中的信息找到 b = 1
的那行的 a 列的值,若是此時咱們把 row group 設小一點,假設就設成 1,這樣對於 b <> 1
的行都不須要解壓 a 列。最後論文中給出一個通常性的建議,建議將 row group 設成 4MB。
而後是 ORC File(Optimized Row Columnar file),對RCFile作了一些優化,克服 RCFile 的一些限制,主要參考這篇文檔。 和RCFile格式相比,ORC File格式有如下優勢:
ORC File包含一組組的行數據,稱爲stripes,除此以外,ORC File的file footer還包含一些額外的輔助信息。在ORC File文件的最後,有一個被稱爲postscript的區,它主要是用來存儲壓縮參數及壓縮頁腳的大小。
在默認狀況下,一個stripe的大小爲250MB。大尺寸的stripes使得從HDFS讀數據更高效。
在file footer裏面包含了該ORC File文件中stripes的信息,每一個stripe中有多少行,以及每列的數據類型。固然,它裏面還包含了列級別的一些聚合的結果,好比:count, min, max, and sum。這裏貼一下文檔上的圖:
每一個Stripe都包含index data、row data以及stripe footer,Stripe footer包含流位置的目錄,Row data在表掃描的時候會用到。
Index data包含每列的最大和最小值以及每列所在的行。行索引裏面提供了偏移量,它能夠跳到正確的壓縮塊位置。
經過行索引,能夠在stripe中快速讀取的過程當中能夠跳過不少行,儘管這個stripe的大小很大。在默認狀況下,最大能夠跳過10000行。
由於能夠經過過濾預測跳過不少行,於是能夠在表的 secondary keys 進行排序,從而能夠大幅減小執行時間。好比你的表的主分區是交易日期,那麼你能夠對次分區(state、zip code以及last name)進行排序。