更高的壓縮比,更好的性能–使用ORC文件格式優化Hive

http://lxw1234.com/archives/2016/04/630.htmapache

關鍵字:orc、index、hive工具

Hive從0.11版本開始提供了ORC的文件格式,ORC文件不單單是一種列式文件存儲格式,最重要的是有着很高的壓縮比,而且對於MapReduce來講是可切分(Split)的。所以,在Hive中使用ORC做爲表的文件存儲格式,不只能夠很大程度的節省HDFS存儲資源,並且對數據的查詢和處理性能有着很是大的提高,由於ORC較其餘文件格式壓縮比高,查詢任務的輸入數據量減小,使用的Task也就減小了。關於Orc文件格式的官網介紹,見:oop

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC性能

須要注意的是,ORC能很大程序的節省存儲和計算資源,但它在讀寫時候須要消耗額外的CPU資源來壓縮和解壓縮,固然這部分的CPU消耗是很是少的。
對性能提高的另外一個方面是經過在ORC文件中爲每個字段創建一個輕量級的索引,來斷定一個文件中是否知足WHERE子句中的過濾條件。好比:當執行HQL語句」SELECT COUNT(1) FROM lxw1234_orc WHERE id = 0」時候,先從ORC文件的metadata中讀取索引信息,快速定位到id=0所在的offsets,若是從索引信息中沒有發現id=0的信息,則直接跳過該文件。詳見後面介紹。
說明一下:本文使用Hive2.0.0 + hadoop-2.3.0-cdh5.0.0做爲測試環境。測試

ORC的壓縮比

hive orc

上圖中原始的TEXT文本文件爲585GB,使用Hive早期的RCFILE壓縮後爲505GB,使用Impala中的PARQUET壓縮後爲221GB,而Hive中的ORC壓縮後僅爲131GB,壓縮比最高。大數據

查看ORC的文件元數據

先準備一張ORC的示例表:優化

  1. CREATE TABLE lxw1234_orc1 (
  2. id INT,
  3. name STRING
  4. ) stored AS ORC;
  5.  
  6. INSERT overwrite TABLE lxw1234_orc1
  7. SELECT CAST(siteid AS INT) AS id,
  8. pcid
  9. FROM lxw1234_text
  10. limit 10;
  11.  
  12. SELECT * FROM lxw1234_orc1 ORDER BY id;
  13. 139 89578071000037563815CC
  14. 139 E811C27809708556F87C79
  15. 633 82E0D8720C8D1556C75ABA
  16. 819 726B86DB00026B56F3F151
  17. 1134 8153CD6F059210539E4552
  18. 1154 5E26977B0EEE5456F7E7FB
  19. 1160 583C0271044D3D56F95436
  20. 1351 FA05CFDD05622756F953EE
  21. 1351 16A5707006C43356F95392
  22. 1361 3C17A17C076A7E56F87CCC

ORC表lxw1234_orc1對應的HDFS文件爲:spa

/hivedata/warehouse2/lxw1234_orc1/000000_0日誌

新版本的Hive中提供了更詳細的查看ORC文件信息的工具 orcfiledump。htm

執行命令:./hive –orcfiledump -j -p /hivedata/warehouse2/lxw1234_orc1/000000_0

返回一段JSON,將其格式化後:

hive orc

schema

hive orc

爲每個字段作了編號,從1開始,編號爲0的columnId中描述了整個表的字段定義。

stripeStatistics

hive orc

這裏是ORC文件中全部stripes的統計信息,其中有每一個stripe中每一個字段的min/max值,是否有空值等等。

fileStatistics

hive orc

這裏是整個文件中每一個字段的統計信息,該表只有一個文件,也只有一個stripe。

stripes

這裏列出了全部stripes的元數據信息,包括index data, row data和stripe footer。

ORC查詢優化

通過上面ORC文件的元數據瞭解了一個ORC文件會被分紅多個stripe,並且文件的元數據中有每一個字段的統計信息(min/max,hasNull等等),這就爲ORC的查詢優化作好了基礎準備。假如個人查詢過濾條件爲WHERE id = 0;在Map Task讀到一個ORC文件時,首先從文件的統計信息中看看id字段的min/max值,若是0不包含在內,那麼這個文件就能夠直接跳過了。
基於這點,還有一個更有效的優化手段是在數據入庫的時候,根據id字段排序後入庫,這樣儘可能能使id=0的數據位於同一個文件甚至是同一個stripe中,那麼在查詢時候,只有負責讀取該文件的Map Task須要掃描文件,其餘的Map Task都會跳過掃描,大大節省Map Task的執行時間。海量數據下,使用ORDER BY可能不太現實,另外一個有效手段是使用DISTRIBUTE BY id SORT BY id;

使用下面的HQL構造一個較大的ORC表:

  1. CREATE TABLE lxw1234_orc2 stored AS ORC
  2. AS
  3. SELECT CAST(siteid AS INT) AS id,
  4. pcid
  5. FROM lxw1234_text
  6. DISTRIBUTE BY id sort BY id;

該語句保證相同的id位於同一個ORC文件中,而且是排序的。

SELECT DISTINCT INPUT__FILE__NAME FROM lxw1234_orc2 WHERE id = 0;

hdfs://cdh5/hivedata/warehouse2/lxw1234_orc2/000000_0

id=0的數據只存在於這一個文件中,而這個表有33個文件。

hive orc

也能夠經過命令

./hive –orcfiledump -j -p hdfs://cdh5/hivedata/warehouse2/lxw1234_orc2/000000_0

查看文件的統計信息:

hive orc

該文件中id的最小值爲0,最大值爲1155.

所以,對於HQL查詢」SELECT COUNT(1) FROM lxw1234_orc2 WHERE id = 0」,優化器在執行時候,只會掃描這一個文件,其餘文件都應該跳過。

 

在驗證以前,先介紹一個參數:

hive.optimize.index.filter,是否自動使用索引,默認爲false(不使用);若是不設置該參數爲true,那麼ORC的索引固然也不會使用。

在Hive中執行set hive.optimize.index.filter=true;

SELECT COUNT(1) FROM lxw1234_orc2 WHERE id = 0;

查看日誌,該查詢一共有13個MapTask,

找到包含/hivedata/warehouse2/lxw1234_orc2/000000_0的MapTask,查看日誌:

hive orc

查看其它MapTask,均沒有掃描記錄的日誌。

不使用索引,再執行一次:

set hive.optimize.index.filter=false;

SELECT COUNT(1) FROM lxw1234_orc2 WHERE id = 0;

再查看日誌時,每一個MapTask中都有掃描記錄的日誌,說明每一個MapTask都對本身的分片進行了掃描。

兩次執行,MapTask的執行時間也能說明問題。

 

使用索引的耗時:

hive orc

不使用索引的耗時(明顯多於上面):

hive orc

 

因而可知,Hive中的ORC不單單有着高壓縮比,很大程序的節省存儲空間和計算資源,並且在其上還作了許多優化(這裏僅僅介紹了row_index)。若是使用Hive做爲大數據倉庫,強烈建議主要使用ORC文件格式做爲表的存儲格式。

相關文章
相關標籤/搜索