hive长尾优化

背景
在刚使用hive的过程中,碰到过很多问题,任务经常需要运行7,8个小时甚至更久,在此记录一下这个过程中,我的一些收获

join长尾
背景
SQL在Join执行阶段会将Join Key相同的数据分发到同一个执行Instance上处理。如果某个Key上的数据量比较多,会导致该Instance执行时间比其他Instance执行时间长。其表现为:执行日志中该Join Task的大部分Instance都已执行完成,但少数几个Instance一直处于执行中,这种现象称之为长尾

长尾类别&优化方法
小表长尾
Join倾斜时,如果某路输入比较小,可以采用Mapjoin避免倾斜。Mapjoin的原理是将Join操作提前到Map端执行,这样可以避免因为分发Key不均匀导致数据倾斜。但是Mapjoin的使用有限制,必须是Join中的从表比较小才可用。所谓从表,即Left Outer Join中的右表,或者Right Outer Join中的左表。

热点值长尾
如果是因为热点值导致长尾,并且Join的输入比较大无法用Mapjoin,可以先将热点Key取出,对于主表数据用热点Key切分成热点数据和非热点数据两部分分别处理,最后合并。我们举一个电商的例子,假设我们需要计算所有商品的pv。我们有如下两张表

日志表 log 用户点击的日志, 包含商品的id p_id
商品表 product 包含商品名称 p_name, 商品id p_id

取热点值, 取商品pv大于10000的商品到临时表

INSERT TABLE topk_product 
SELECT
	  distinct p_id
FROM
	(
		SELECT
			p_id,
			count(1) AS pv
		FROM log
		GROUP BY p_id
	) a
WHERE pv >= 10000

取出非热点值和商品(product) join 得到非热点商品的pv

SELECT p.p_id
	, p.p_name
	, l.pv
FROM (
	SELECT p_id
		, p_name
	FROM product
) p
JOIN (
	SELECT /*+mapjoin(b)*/ a.*
	FROM (
		SELECT p_id
			, COUNT(1) AS pv
		FROM log
	) a
	LEFT OUTER JOIN (
		SELECT p_id
		FROM topk_product
	) b
	ON a.p_id = b.p_id
		AND b.p_id IS NULL
) l
ON p.p_id = l.p_id

取出热点值和商品(product) join 得到热点商品的pv

SELECT p.p_id
	, p.p_name
	, l.pv
FROM (
	SELECT /*+mapjoin(b)*/ a.*
	FROM (
		SELECT p_id
			, p_name
		FROM product
	) a
	JOIN (
		SELECT p_id
		FROM topk_product
	) b
	ON a.p_id = b.p_id
) p
JOIN (
	SELECT /*+mapjoin(d)*/ c.*
	FROM (
		SELECT p_id
			, COUNT(1) AS pv
		FROM log
	) c
	JOIN (
		SELECT p_id
		FROM topk_product
	) d
	ON c.p_id = d.p_id
) l
ON p.p_id = l.p_id

union all 热点和非热点的数据
空值长尾
join时,假设左表(left_table)存在大量的空值,空值聚集到一个reduce上。由于left_table 存在大量的记录,无法使用mapjoin 。此时可以使用 coalesce(left_table.key, rand()*9999)将key为空的情况下赋予随机值,来避免空值集中造成长尾。

map长尾
Map端读取数据时,由于文件大小分布不均匀,一些map任务读取并处理的数据特别多,一些map任务处理的数据特别少,造成map端长尾。这种情形没有特别好的方法,只能调节splitsize来增加mapper数量,让数据分片更小,以期望获得更均匀的分配。

reduce长尾
由于Distinct操作的存在,数据无法在Map端的Shuffle阶段根据Group By先做一次聚合操作,减少传输的数据量,而是将所有的数据都传输到Reduce端,当Key的数据分发不均匀时,就会导致Reduce端长尾,特别当多个Distinct同时出现在一段SQL代码中时,数据会被分发多次,不仅会造成数据膨胀N倍,也会把长尾现象放大N倍。

我们用代码举个例子:

只有一个distinct 的情况
原sql

SELECT D1
	, D2
	, COUNT(DISTINCT CASE 
		WHEN A IS NOT NULL THEN B
	END) AS B_distinct_cnt
FROM xxx
GROUP BY D1, 
	D2

改后的sql

create table tmp1
as
select D1,D2,B,
count( case when A is not null then B end ) as B_cnt
from xxx
group by D1, D1, B


select D1,D2,
sum(case when B_cnt > 0 then 1 else 0 end) as B_distinct_cnt
from tmp1
group by D1,D2

多个distinct的情况
原始sql

select D1,D2,
count(distinct case when A is not null then B end) as B_distinct_cnt ,
count(distinct case when E is not null then C end) as C_distinct_cnt 
from xxx group by D1,D2

修改后的sql

create table tmp1
as
select D1,D2,B,
count( case when A is not null then B end ) as B_cnt
from xxx
group by D1, D1, B

create table tmp1_1
as
select D1,D2,
sum(case when B_cnt > 0 then 1 else 0 end) as B_distinct_cnt
from tmp1
group by D1,D2

create table tmp2
as
select D1,D2,C,
count( case when E is not null then C end ) as C_cnt
from xxx
group by D1, D1, C

create table tmp2_1
as
select D1,D2,
sum(case when C_cnt > 0 then 1 else 0 end) as C_distinct_cnt
from tmp1
group by D1,D2

select 
t1.D1,t1.D2,
t1.B_distinct_cnt,
t2.C_distinct_cnt
from tmp1_1 t1
left outer join tmp2_1 t2
on t1.D1=t2.D1 and t1.D2=t2.D2

原文地址:
https://www.cnblogs.com/duanxingxing/p/6874318.html

<think>好的,我需要帮助用户解决Hive查询性能差异的原因以及如何优化Java程序中通过YML文件连接Hive数据库的配置。首先,我需要理清Hive查询性能差异的可能因素。Hive是基于Hadoop的数据仓库工具,性能受多个方面影响,比如数据倾斜、分区和分桶策略、文件格式、资源配置、执行引擎以及查询语句本身的优化等。需要逐一分析这些因素。 然后,用户提到Java程序中通过YML文件连接Hive的配置。YML通常用于Spring Boot项目,配置数据源连接。这里需要检查连接池配置、Hive JDBC参数、资源分配以及可能的Kerberos认证设置。比如连接池的大小不合理可能导致性能问题,JDBC的超时设置不正确会影响查询响应。 接下来,我需要结合引用中的内容。引用[1]提到了内存数据库、CQRS模式、事件溯源等优化策略,虽然这些主要针对实时系统,但可以部分借鉴,比如使用更高效的数据存储格式(如ORC、Parquet)来优化Hive查询。引用[2]提到分库分表,但Hive本身是数据仓库,分区分桶可能更相关,不过DAL框架的问题可能提醒要注意避免ORM的笨重,保持查询的灵活性。 在解决方案部分,需要分点说明性能优化的方法,包括数据模型优化、配置参数调整、执行引擎选择(如Tez或Spark)、资源管理和查询优化技巧。对于YML配置,要给出具体的配置示例,如Hikari连接池的参数,以及Hive JDBC的URL格式,确保用户能直接应用。 最后,生成相关问题时要围绕Hive性能调优和配置,可能涉及执行引擎比较、数据倾斜处理、文件格式选择等,确保问题覆盖用户可能进一步的需求。</think>### Hive查询性能差异原因分析及优化方案 #### 一、Hive查询性能差异的主要原因 1. **数据分布特征** - 数据倾斜会导致某些Reduce任务负载过高,形成长尾效应$^{[典型场景]}$ - 未使用分区表或分桶表时,全表扫描会显著增加IO开销 2. **执行引擎差异** - MapReduce引擎与Tez/Spark引擎性能对比: $$T_{MR} = N_{map} \times t_{map} + N_{reduce} \times t_{reduce}$$ $$T_{Tez} = \sum_{stage} (并行化流水线执行时间)$$ 3. **配置参数影响** - `hive.exec.parallel`(是否启用并行执行) - `hive.auto.convert.join`(自动优化MapJoin) - `hive.vectorized.execution.enabled`(向量化执行) #### 二、YML连接配置优化示例 ```yaml spring: datasource: hive: jdbc-url: jdbc:hive2://hiveserver:10000/default;tez.queue.name=prod driver-class-name: org.apache.hive.jdbc.HiveDriver hikari: maximum-pool-size: 20 # 根据集群规模调整 connection-timeout: 30000 validation-timeout: 5000 properties: hive.resultset.use.unique.column.names: false hive.fetch.task.conversion: more ``` #### 三、性能优化实施路径 1. **数据模型优化** - 建立分层分区(年/月/日) - 对高频查询字段进行分桶 - 使用ORC文件格式并创建布隆过滤器 2. **执行参数调优** ```sql SET hive.vectorized.execution.enabled=true; SET hive.optimize.sort.dynamic.partition=true; SET hive.auto.convert.join.noconditionaltask.size=512000000; ``` 3. **资源管理策略** - YARN队列资源配置(参考引用[1]的实时监控方案) - 结合CQRS模式分离读写操作(如引用[1]所述) 4. **查询优化技巧** - 避免`SELECT *`查询 - 使用谓词下推(Predicate Pushdown) - 对JOIN操作进行顺序优化 #### 四、配置验证方法 1. 使用`EXPLAIN`解析执行计划 2. 通过HiveServer2日志分析连接问题 3. 使用JMeter进行JDBC压力测试
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值