原文引自:http://www.tbdata.org/archives/622
使用Hive可以高效而又快速地编写复杂的MapReduce查询逻辑。但是某些情况下,因为不熟悉数据特性,或没有遵循Hive的优化约定,Hive计算任务会变得非常低效,甚至无法得到结果。一个”好”的Hive程序仍然需要对Hive运行机制有深入的了解。
有一些大家比较熟悉的优化约定包括:Join中需要将大表写在靠右的位置;尽量使用UDF而不是transfrom……诸如此类。下面讨论5个性能和逻辑相关的问题,帮助你写出更好的Hive程序。
全排序
Hive的排序关键字是SORT BY,它有意区别于传统数据库的ORDER BY也是为了强调两者的区别–SORT BY只能在单机范围内排序。考虑以下表定义:
CREATE TABLE if not exists t_order( id int, -- 订单编号 sale_id int, -- 销售ID customer_id int, -- 客户ID product _id int, -- 产品ID amount int -- 数量 ) PARTITIONED BY (ds STRING);
在表中查询所有销售记录,并按照销售ID和数量排序:
set mapred.reduce.tasks=2; Select sale_id, amount from t_order Sort by sale_id, amount;
这一查询可能得到非期望的排序。指定的2个reducer分发到的数据可能是(各自排序):
Reducer1:
Sale_id | amount 0 | 100 1 | 30 1 | 50 2 | 20
Reducer2:
Sale_id | amount 0 | 110 0 | 120 3 | 50 4 | 20
因为上述查询没有reduce key,hive会生成随机数作为reduce key。这样的话输入记录也随机地被分发到不同reducer机器上去了。为了保证reducer之间没有重复的sale_id记录,可以使用DISTRIBUTE BY关键字指定分发key为sale_id。改造后的HQL如下:
set mapred.reduce.tasks=2; Select sale_id, amount from t_order Distribute by sale_id Sort by sale_id, amount;
这样能够保证查询的销售记录集合中,销售ID对应的数量是正确排序的,但是销售ID不能正确排序,原因是hive使用hadoop默认的HashPartitioner分发数据。
这就涉及到一个全排序的问题。解决的办法无外乎两种:
1.) 不分发数据,使用单个reducer:
set mapred.reduce.tasks=1;
这一方法的缺陷在于reduce端成为了性能瓶颈,而且在数据量大的情况下一般都无法得到结果。但是实践中这仍然是最常用的方法,原因是通常排序的查询是为了得到排名靠前的若干结果,因此可以用limit子句大大减少数据量。使用limit n后,传输到reduce端(单机)的数据记录数就减少到n* (map个数)。
2.) 修改Partitioner,这种方法可以做到全排序。这里可以使用Hadoop自带的TotalOrderPartitioner(来自于Yahoo!的TeraSort项目),这是一个为了支持跨reducer分发有序数据开发的Partitioner,它需要一个SequenceFile格式的文件指定分发的数据区间。如果我们已经生成了这一文件(存储在/tmp/range_key_list,分成100个reducer),可以将上述查询改写为
set mapred.reduce.tasks=100; set hive.mapred.partitioner=org.apache.hadoop.mapred.lib.TotalOrderPartitioner; set total.order.partitioner.path=/tmp/ range_key_list; Select sale_id, amount from t_order Cluster by sale_id Sort by amount;
有很多种方法生成这一区间文件(例如hadoop自带的o.a.h.mapreduce.lib.partition.InputSampler工具)。这里介绍用Hive生成的方法,例如有一个按id有序的t_sale表:
CREATE TABLE if not exists t_sale ( id int, name string, loc string );
则生成按sale_id分发的区间文件的方法是:
create external table range_keys(sale_id int) row format serde 'org.apache.hadoop.hive.serde2.binarysortable.BinarySortableSerDe' stored as inputformat 'org.apache.hadoop.mapred.TextInputFormat' outputformat 'org.apache.hadoop.hive.ql.io.HiveNullValueSequenceFileOutputFormat' location '/tmp/range_key_list'; insert overwrite table range_keys select distinct sale_id from source t_sale sampletable(BUCKET 100 OUT OF 100 ON rand()) s sort by sale_id;
生成的文件(/tmp/range_key_list目录下)可以让TotalOrderPartitioner按sale_id有序地分发reduce处理的数据。区间文件需要考虑的主要问题是数据分发的均衡性,这有赖于对数据深入的理解。
怎样做笛卡尔积?
当Hive设定为严格模式(hive.mapred.mode=strict)时,不允许在HQL语句中出现笛卡尔积,这实际说明了Hive对笛卡尔积支持较弱。因为找不到Join key,Hive只能使用1个reducer来完成笛卡尔积。
当然也可以用上面说的limit的办法来减少某个表参与join的数据量,但对于需要笛卡尔积语义的需求来说,经常是一个大表和一个小表的Join操作,结果仍然很大(以至于无法用单机处理),这时MapJoin才是最好的解决办法。
MapJoin,顾名思义,会在Map端完成Join操作。这需要将Join操作的一个或多个表完全读入内存。
MapJoin的用法是在查询/子查询的SELECT关键字后面添加/*+ MAPJOIN(tablelist) */提示优化器转化为MapJoin(目前Hive的优化器不能自动优化MapJoin)。其中tablelist可以是一个表,或以逗号连接的表的列表。tablelist中的表将会读入内存,应该将小表写在这里。
PS:有用户说MapJoin在子查询中可能出现未知BUG。在大表和小表做笛卡尔积时,规避笛卡尔积的方法是,给Join添加一个Join key,原理很简单:将小表扩充一列join key,并将小表的条目复制数倍,join key各不相同;将大表扩充一列join key为随机数。
怎样写exist in子句?
Hive不支持where子句中的子查询,SQL常用的exist in子句需要改写。这一改写相对简单。考虑以下SQL查询语句:
SELECT a.key, a.value FROM a WHERE a.key in (SELECT b.key FROM B);
可以改写为
SELECT a.key, a.value FROM a LEFT OUTER JOIN b ON (a.key = b.key) WHERE b.key <> NULL;
一个更高效的实现是利用left semi join改写为:
SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key);
left semi join是0.5.0以上版本的特性。
Hive怎样决定reducer个数?
Hadoop MapReduce程序中,reducer个数的设定极大影响执行效率,这使得Hive怎样决定reducer个数成为一个关键问题。遗憾的是Hive的估计机制很弱,不指定reducer个数的情况下,Hive会猜测确定一个reducer个数,基于以下两个设定:
1. hive.exec.reducers.bytes.per.reducer(默认为1000^3)
2. hive.exec.reducers.max(默认为999)
计算reducer数的公式很简单:
通常情况下,有必要手动指定reducer个数。考虑到map阶段的输出数据量通常会比输入有大幅减少,因此即使不设定reducer个数,重设参数2还是必要的。依据Hadoop的经验,可以将参数2设定为0.95*(集群中TaskTracker个数)。
合并MapReduce操作
Multi-group by
Multi-group by是Hive的一个非常好的特性,它使得Hive中利用中间结果变得非常方便。例如,
FROM (SELECT a.status, b.school, b.gender FROM status_updates a JOIN profiles b ON (a.userid = b.userid and a.ds='2009-03-20' ) ) subq1 INSERT OVERWRITE TABLE gender_summary PARTITION(ds='2009-03-20') SELECT subq1.gender, COUNT(1) GROUP BY subq1.gender INSERT OVERWRITE TABLE school_summary PARTITION(ds='2009-03-20') SELECT subq1.school, COUNT(1) GROUP BY subq1.school
上述查询语句使用了Multi-group by特性连续group by了2次数据,使用不同的group by key。这一特性可以减少一次MapReduce操作。
Multi-distinct
Multi-distinct是淘宝开发的另一个multi-xxx特性,使用Multi-distinct可以在同一查询/子查询中使用多个distinct,这同样减少了多次MapReduce操作。
分享到:
相关推荐
标题中提到的“写好Hive程序的五个提示”指向了在大数据领域内使用Hive语言编写的程序优化和最佳实践。Hive作为一个建立在Hadoop之上的数据仓库工具,可以将SQL语句转换为MapReduce任务进行执行,非常适合处理大数据...
在IT行业中,数据库管理和分析是至关重要的任务,而Hive作为一个大数据处理的仓库系统,它提供了对结构化数据的查询和分析能力。当需要通过图形化的数据库管理工具,如DBeaver,与Hive进行交互时,就需要用到特定的...
在大数据处理领域,Hive...Hive JDBC驱动程序允许Java应用程序通过JDBC接口与Hive通信,这使得像DataGrip这样的工具能够无缝地与Hive交互。掌握这些知识和步骤,你就可以更便捷地管理和分析存储在Hadoop上的大数据了。
这个文件可能包含Apache Hive的Java驱动程序,使得DataGrip能够理解并执行HQL语句。 在Hadoop生态系统中,Hive是构建在HDFS(Hadoop分布式文件系统)之上,提供了一种结构化的数据处理方式。它将数据存储在HDFS中,...
2. **Hive-HWI介绍**:Hive-HWI是一个轻量级的Web应用程序,它提供了一个图形化界面,用户可以在这个界面上创建Hive表、执行HQL查询、查看查询结果等,极大地提高了用户的交互体验。 3. **安装Hive-HWI**:首先,你...
5. **测试连接**:点击“Test Connection”按钮,如果配置正确,你应该能看到“Connection successful”的提示。 6. **连接Hive**:确认连接成功后,点击“Connect”按钮,SQuirrel SQL Client将连接到Hive服务器,...
完成以上步骤后,你的IDEA项目就配置好了连接CDH集群中Hive组件的能力,可以编写Java程序执行Hive查询,进行大数据分析工作。记得在实际操作时,确保集群的网络安全设置允许从你的开发机器访问,并且配置文件正确...
在大数据分析领域,Hive是一个基于Hadoop的数据仓库工具,它可以将结构化的数据文件映射为一张数据库表,并提供SQL查询功能,使得分析师能够通过SQL语句对存储在Hadoop集群上的大规模数据进行处理和分析。...
### Hive安装知识点详解 #### 一、Hive简介与安装目的 Hive 是基于 Hadoop 的数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的 SQL 查询功能,可以将 SQL 语句转换为 MapReduce 任务进行运行...
总之,Hive ODBC驱动程序为Windows用户提供了便利的数据接入途径,使得Hadoop生态中的Hive数据仓库能够更好地服务于数据分析和业务决策,实现大数据的充分利用。无论是数据科学家、分析师还是业务人员,都能从中受益...
Apache Hive 是一个构建在Hadoop生态系统之上的数据仓库工具,其设计目的是为了简化对大量分布式存储数据的管理和分析。Hive 提供了SQL(结构化查询语言)接口,使得非编程背景的用户也能轻松地对大数据进行操作。...
总之,Hive作为一个强大的数据仓库工具,在CDH 5.5.0环境中提供了丰富的功能和灵活性。通过对Hive的基本使用和高级特性有了深入理解之后,用户可以更有效地利用Hadoop集群来管理和分析大规模的数据集。
安装这两个驱动后,用户可以通过Tableau或其他支持ODBC的应用程序,如Excel、Python等,轻松地连接到Hadoop集群中的Hive或Impala服务,执行SQL查询并获取结果。 在实际操作中,安装这些驱动通常包括以下步骤: 1. ...
JDBC API v3.x支持JRE v4.0或v5.0 JDBC API v4.x支持JRE v6.0或更高版本JDBC API v4.1.x支持JRE v7.0或更高版本适用于Apache Hive的Cloudera JDBC驱动程序支持Hive 0.11、0.12、0.13、0.14、1.0和1.1。 有关更多...
语言:English (United States) 在WordPress.ORG中显示插件报告 ...该扩展程序还提供了一个选项,可以重定向到特定插件的WP Hive插件页面。 当然,WordPress存储库很棒,但是WP Hive通过更好的洞察力使其更加
标签“Python库”提示我们,`hive_builder`是一个Python编程语言的软件包,可能提供与Hadoop Hive相关的功能,如创建Hive表、执行HQL查询、管理Hive元数据等。Python库通常通过`setup.py`文件进行安装,开发者可以...
这个JAR文件是用于Kettle连接Hive的驱动程序,使得Kettle能够与Hive进行通信,执行查询和数据操作。这里的"1.1.0"是Hive的版本号,而"cdh5.16.2"则指的是Cloudera Data Hub (CDH)的一个特定版本,CDH是一个流行的...
Python 组件的框架 hive 系统可用于可视化编程、大型 3D 应用程序、游戏逻辑和科学协议当前待办事项启用从 Hive GUI 导出/导入 hivemaps [完成] 尽可能镜像现有的 Logic Brick 支持为工作人员实施工具提示简化 ...