在 Apache Hive 中轻松生存的12个技巧
Hive 可以让你在 Hadoop 上使用 SQL，但是在分布式系统上优化 SQL 则有所不同。这里是让你可以轻松驾驭 Hive 的12个技巧。
SQL Hadoop Hive 数据库
Hive 可以让你在 Hadoop 上使用 SQL，但是在分布式系统上优化 SQL 则有所不同。这里是让你可以轻松驾驭 Hive 的12个技巧。
![Learn to live with Apache Hive in 12 easy steps](/data/attachment/album/201604/07/121431g4blm1oczk811umc.jpg)


Hive 可以让你在 Hadoop 上使用 SQL，但是在分布式系统上优化 SQL 则有所不同。这里是让你可以轻松驾驭 Hive 的12个技巧。


[Hive](http://www.infoworld.com/article/2608271/hadoop/hadoop-review-apache-hive-brings-real-time-queries-to-hadoop.html) 并不是关系型数据库（RDBMS），但是它大多数时候都表现得像是一个关系型数据库一样，它有表、可以运行 SQL、也支持 JDBC 和 ODBC。


这种表现既有好的一面，也有不好的一面：Hive 并不像关系型数据库那样执行 SQL 查询。我在 Hive 上花费了大量时间，光是我自己在工作中就为了优化它花费了超过80个小时。不说你也知道，我就像呆在蜂巢（Hive）旁边一样脑袋嗡嗡作响。所以，为了让你免受这种痛苦，我决定将它们写出来，以便让你在你的下一个 Hive 项目中逃离这种折磨。


### 1、不要使用 MapReduce


不管你是不是觉得 Tez、Spark 或 Impala 能行，但是不要指望 MapReduce。它本身就很慢，比 Hive 还慢。如果你用的是 Hortonwork 的版本，你可以在脚本前面写上 `set hive.execution.engine=tez` ；用 Cloudera 的话，使用 Impala。如果 Impala 不适用的话，我[希望到时候](http://www.cloudera.com/documentation/enterprise/latest/topics/admin_hos_config.html)可以使用 `hive.execution.engine=spark` 。


### 2、不要在 SQL 中做字符串匹配


绝不要，特别是在 Hive 中！如果你坚持要在 WHERE 语句中使用 LIKE 匹配，就会产生一个跨产品的警告。本来你的查询可能只用几秒钟，但是使用字符串匹配的话就会变成几分钟。最好的办法是使用那些可以在 Hadoop 中进行搜索的工具，可以试试 [Elasticsearch 的 Hive 集成版本](https://www.elastic.co/guide/en/elasticsearch/hadoop/current/hive.html) 或 [Lucidwork 的 Solr](https://github.com/lucidworks/hive-solr/blob/master/README.adoc)，以及 [Cloudera Search](https://cloudera.com/products/apache-hadoop/apache-solr.html)。关系型数据库这方面表现并不好，但是 Hive 则更糟糕。


### 3、不要用表连接子查询


你最好创建一个临时表，然后对这个临时表进行连接，而不是让 Hive 自己智能处理子查询。即不要这样做：



```
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
```

而是应该这样：



```
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
```

一般来说，这会比 Hive 自己处理子查询要快许多。


### 4、使用 Parquet 或 ORC，但是不要转换使用


也就是说，使用 Parquet 或 ORC 而不要用 TEXTFILE。然而，如果你要把文本数据中导入到更具结构性的数据中，应该做一些转换再导入到目标表中。你不应该用 `LOAD DATA` 将文本文件加载到 ORC 中，而是应该将其加载到一个文本中。


如果你要创建另外一个表，并最终大多数分析都是对它进行的，那么你就该对该表进行 ORC 化，因为转换到 ORC 或 Parquet 要花费很多时间，并不值得将其放到你的 ETL 处理中。如果你有一个简单的普通文本要导入，也没做过任何优化，你应该将其加载到一个临时表并通过 `select create` 放到 ORC 或 Parquet 中。不过，这有点慢。


### 5、开关矢量化试试


在你的脚本前面加上 `set hive.vectorized.execution.enabled = true` 和`set hive.vectorized.execution.reduce.enabled = true` ，然后试着打开或关闭它们看看。因为最近版本的 Hive 的矢量化有点问题。


### 6、不要在表连接中使用 structs


我必须承认我大脑里面的 SQL 格式还是 SQL-92 时代的，所以我无论如何都不会想到去用 [structs](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types)。但是如果你做一些超级复杂的操作，比如在联合主键上使用 `ON` 语句，那么 structs 就很方便。不幸的是，Hive 对它们很不适应，特别是在 `ON` 语句上。当然，大多数情况下，在较小的数据集和 yields 下是没错误的。在 Tez 里面，你会得到一个有趣的矢量错误。这个限制并未见于我所知的任何文档，也许这是一个探索你的执行引擎内部的好办法。


### 7、检查你的容器大小


你也许需要为 [Impala](http://www.cloudera.com/documentation/enterprise/5-3-x/topics/cdh_ig_yarn_tuning.html) 或 [Tez](https://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.2/bk_performance_tuning/content/hive_perf_best_pract_config_tez.html) 增加你的容器大小。如果有你的节点大小比较大，“推荐的”容器大小可能就不适用于你的系统。你也许需要确保你的 YARN 队列和常规的 YARN 内存大小合适。你也许应该[注意默认的队列并不适合](https://community.cloudera.com/t5/Batch-SQL-Apache-Hive/How-can-I-submit-Hive-queries-via-Beeline-to-specific-resource/td-p/19324)所有的常规使用。


### 8、启用统计


Hive 在表连接时[会做一些蠢事](https://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.2/bk_performance_tuning/content/hive_perf_best_pract_use_col_stats_cost_base_opt.html)，除非[启用了统计](http://www.cloudera.com/documentation/enterprise/5-3-x/topics/impala_perf_joins.html?scroll=perf_joins)。你也可以[在 Impala 中使用查询提示](http://www.cloudera.com/documentation/enterprise/5-3-x/topics/impala_hints.html?scroll=hints)。


### 9、考虑 [MapJoin 优化](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+JoinOptimization)


如果你分析你的查询，你可能发现最新的 Hive 已经可以足够智能地进行自动优化了。但是你也许需要再调整一下。


### 10、如果可以，[将大表放到最后](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Joins)


如标题。


### 11、分区总会帮到你，不管多少


如果你有一个出现在许多地方的东西，比如语句中的日期（但不是日期范围）或重复的地点，你也许应该做分区。分区的基本意思是“拆分到它自己的目录里面”，而不是到一个大的文件中去查找。当你在你的 join/where 语句中仅检索 `location=’NC’`这样一个小数据集时，Hive 就可以在一个文件中查找。此外，和列值不同，你可以在你的 `LOAD DATA` 语句中加上分区。另外，要记住，[HDFS 并不喜欢小文件](http://blog.cloudera.com/blog/2009/02/the-small-files-problem/)。


### 12、使用哈希进行列比较


如果你要在每个查询中比较同样的10个字段，可以考虑使用 `hash()` 来比较它们的校验值。在一个输出表中展示它们也许很有用。注意，在 Hive 0.12 中，哈希功能比较差，0.13中的哈希更好一些。


以上就是我的12点经验，我希望这些能够帮到你，让你从 Hive 的嗡嗡声中逃离出来。 

