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做爲測試環境。測試
上圖中原始的TEXT文本文件爲585GB,使用Hive早期的RCFILE壓縮後爲505GB,使用Impala中的PARQUET壓縮後爲221GB,而Hive中的ORC壓縮後僅爲131GB,壓縮比最高。大數據
先準備一張ORC的示例表:優化
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,將其格式化後:
爲每個字段作了編號,從1開始,編號爲0的columnId中描述了整個表的字段定義。
這裏是ORC文件中全部stripes的統計信息,其中有每一個stripe中每一個字段的min/max值,是否有空值等等。
這裏是整個文件中每一個字段的統計信息,該表只有一個文件,也只有一個stripe。
這裏列出了全部stripes的元數據信息,包括index data, row data和stripe footer。
通過上面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表:
該語句保證相同的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 –orcfiledump -j -p hdfs://cdh5/hivedata/warehouse2/lxw1234_orc2/000000_0
查看文件的統計信息:
該文件中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,查看日誌:
查看其它MapTask,均沒有掃描記錄的日誌。
不使用索引,再執行一次:
set hive.optimize.index.filter=false;
SELECT COUNT(1) FROM lxw1234_orc2 WHERE id = 0;
再查看日誌時,每一個MapTask中都有掃描記錄的日誌,說明每一個MapTask都對本身的分片進行了掃描。
兩次執行,MapTask的執行時間也能說明問題。
使用索引的耗時:
不使用索引的耗時(明顯多於上面):
因而可知,Hive中的ORC不單單有着高壓縮比,很大程序的節省存儲空間和計算資源,並且在其上還作了許多優化(這裏僅僅介紹了row_index)。若是使用Hive做爲大數據倉庫,強烈建議主要使用ORC文件格式做爲表的存儲格式。