在 Apache Hive 中輕松生存的12個(gè)技巧
Hive 可以讓你在 Hadoop 上使用 SQL,但是在分布式系統(tǒng)上優(yōu)化 SQL 則有所不同。這里是讓你可以輕松駕馭 Hive 的12個(gè)技巧。
Hive 并不是關(guān)系型數(shù)據(jù)庫(kù)(RDBMS),但是它大多數(shù)時(shí)候都表現(xiàn)得像是一個(gè)關(guān)系型數(shù)據(jù)庫(kù)一樣,它有表、可以運(yùn)行 SQL、也支持 JDBC 和 ODBC。
這種表現(xiàn)既有好的一面,也有不好的一面:Hive 并不像關(guān)系型數(shù)據(jù)庫(kù)那樣執(zhí)行 SQL 查詢(xún)。我在 Hive 上花費(fèi)了大量時(shí)間,光是我自己在工作中就為了優(yōu)化它花費(fèi)了超過(guò)80個(gè)小時(shí)。不說(shuō)你也知道,我就像呆在蜂巢(Hive)旁邊一樣腦袋嗡嗡作響。所以,為了讓你免受這種痛苦,我決定將它們寫(xiě)出來(lái),以便讓你在你的下一個(gè) Hive 項(xiàng)目中逃離這種折磨。
1、不要使用 MapReduce
不管你是不是覺(jué)得 Tez、Spark 或 Impala 能行,但是不要指望 MapReduce。它本身就很慢,比 Hive 還慢。如果你用的是 Hortonwork 的版本,你可以在腳本前面寫(xiě)上 set hive.execution.engine=tez ;用 Cloudera 的話(huà),使用 Impala。如果 Impala 不適用的話(huà),我 希望到時(shí)候 可以使用 hive.execution.engine=spark 。
2、不要在 SQL 中做字符串匹配
絕不要,特別是在 Hive 中!如果你堅(jiān)持要在 WHERE 語(yǔ)句中使用 LIKE 匹配,就會(huì)產(chǎn)生一個(gè)跨產(chǎn)品的警告。本來(lái)你的查詢(xún)可能只用幾秒鐘,但是使用字符串匹配的話(huà)就會(huì)變成幾分鐘。***的辦法是使用那些可以在 Hadoop 中進(jìn)行搜索的工具,可以試試 Elasticsearch 的 Hive 集成版本或 Lucidwork 的 Solr ,以及 Cloudera Search 。關(guān)系型數(shù)據(jù)庫(kù)這方面表現(xiàn)并不好,但是 Hive 則更糟糕。
3、不要用表連接子查詢(xún)
你***創(chuàng)建一個(gè)臨時(shí)表,然后對(duì)這個(gè)臨時(shí)表進(jìn)行連接,而不是讓 Hive 自己智能處理子查詢(xún)。即不要這樣做:
- select a.* from something a inner join
- (select ... from somethingelse union b select ... from anotherthing c) d
- on a.key1 = d.key1 and a.key2 = b.key2 where a.condition=1
而是應(yīng)該這樣:
- create var_temp as select ... from somethingelse b
- union select ... from anotherthing c
- and then
- select a.* from something a inner join from var_temp b
- where a.key1=b.key1 and a.key2=b.key2 where a.condition=1
一般來(lái)說(shuō),這會(huì)比 Hive 自己處理子查詢(xún)要快許多。
4、使用 Parquet 或 ORC,但是不要轉(zhuǎn)換使用
也就是說(shuō),使用 Parquet 或 ORC 而不要用 TEXTFILE。然而,如果你要把文本數(shù)據(jù)中導(dǎo)入到更具結(jié)構(gòu)性的數(shù)據(jù)中,應(yīng)該做一些轉(zhuǎn)換再導(dǎo)入到目標(biāo)表中。你不應(yīng)該用 LOAD DATA 將文本文件加載到 ORC 中,而是應(yīng)該將其加載到一個(gè)文本中。
如果你要?jiǎng)?chuàng)建另外一個(gè)表,并最終大多數(shù)分析都是對(duì)它進(jìn)行的,那么你就該對(duì)該表進(jìn)行 ORC 化,因?yàn)檗D(zhuǎn)換到 ORC 或 Parquet 要花費(fèi)很多時(shí)間,并不值得將其放到你的 ETL 處理中。如果你有一個(gè)簡(jiǎn)單的普通文本要導(dǎo)入,也沒(méi)做過(guò)任何優(yōu)化,你應(yīng)該將其加載到一個(gè)臨時(shí)表并通過(guò) select create 放到 ORC 或 Parquet 中。不過(guò),這有點(diǎn)慢。
5、開(kāi)關(guān)矢量化試試
在你的腳本前面加上 set hive.vectorized.execution.enabled = true 和 set hive.vectorized.execution.reduce.enabled = true ,然后試著打開(kāi)或關(guān)閉它們看看。因?yàn)樽罱姹镜?Hive 的矢量化有點(diǎn)問(wèn)題。
6、不要在表連接中使用 structs
我必須承認(rèn)我大腦里面的 SQL 格式還是 SQL-92 時(shí)代的,所以我無(wú)論如何都不會(huì)想到去用 structs 。但是如果你做一些超級(jí)復(fù)雜的操作,比如在聯(lián)合主鍵上使用 ON 語(yǔ)句,那么 structs 就很方便。不幸的是,Hive 對(duì)它們很不適應(yīng),特別是在 ON 語(yǔ)句上。當(dāng)然,大多數(shù)情況下,在較小的數(shù)據(jù)集和 yields 下是沒(méi)錯(cuò)誤的。在 Tez 里面,你會(huì)得到一個(gè)有趣的矢量錯(cuò)誤。這個(gè)限制并未見(jiàn)于我所知的任何文檔,也許這是一個(gè)探索你的執(zhí)行引擎內(nèi)部的好辦法。
7、檢查你的容器大小
你也許需要為 Impala 或 Tez 增加你的容器大小。如果有你的節(jié)點(diǎn)大小比較大,“推薦的”容器大小可能就不適用于你的系統(tǒng)。你也許需要確保你的 YARN 隊(duì)列和常規(guī)的 YARN 內(nèi)存大小合適。你也許應(yīng)該 注意默認(rèn)的隊(duì)列并不適合 所有的常規(guī)使用。
8、啟用統(tǒng)計(jì)
Hive 在表連接時(shí) 會(huì)做一些蠢事 ,除非 啟用了統(tǒng)計(jì) 。你也可以 在 Impala 中使用查詢(xún)提示 。
9、考慮 MapJoin 優(yōu)化
如果你分析你的查詢(xún),你可能發(fā)現(xiàn)***的 Hive 已經(jīng)可以足夠智能地進(jìn)行自動(dòng)優(yōu)化了。但是你也許需要再調(diào)整一下。
10、如果可以, 將大表放到***
如標(biāo)題。
11、分區(qū)總會(huì)幫到你,不管多少
如果你有一個(gè)出現(xiàn)在許多地方的東西,比如語(yǔ)句中的日期(但不是日期范圍)或重復(fù)的地點(diǎn),你也許應(yīng)該做分區(qū)。分區(qū)的基本意思是“拆分到它自己的目錄里面”,而不是到一個(gè)大的文件中去查找。當(dāng)你在你的 join/where 語(yǔ)句中僅檢索 location=’NC’ 這樣一個(gè)小數(shù)據(jù)集時(shí),Hive 就可以在一個(gè)文件中查找。此外,和列值不同,你可以在你的 LOAD DATA 語(yǔ)句中加上分區(qū)。另外,要記住, HDFS 并不喜歡小文件 。
12、使用哈希進(jìn)行列比較
如果你要在每個(gè)查詢(xún)中比較同樣的10個(gè)字段,可以考慮使用 hash() 來(lái)比較它們的校驗(yàn)值。在一個(gè)輸出表中展示它們也許很有用。注意,在 Hive 0.12 中,哈希功能比較差,0.13中的哈希更好一些。
以上就是我的12點(diǎn)經(jīng)驗(yàn),我希望這些能夠幫到你,讓你從 Hive 的嗡嗡聲中逃離出來(lái)。