hive的优化有哪些实用方法,如何提升查询效率

文章摘要

hive的优化中SQL语句如何调整写hive SQL的时候,很多人觉得只要能跑出结果就行,其实里面藏着不少优化门道,我之前帮一个电商公司做数据统计,他们有个查询要从3亿条订单数据里筛选近三个月的高价值用户,一开始写的SQL跑了快40分钟,老板急得直转圈,后来我一看,发现问题出在全表扫描上——他们用了“selec……

hive的优化中SQL语句如何调整

写hive SQL的时候,很多人觉得只要能跑出结果就行,其实里面藏着不少优化门道,我之前帮一个电商公司做数据统计,他们有个查询要从3亿条订单数据里筛选近三个月的高价值用户,一开始写的SQL跑了快40分钟,老板急得直转圈,后来我一看,发现问题出在全表扫描上——他们用了“select *”,还没加分区过滤,就像在图书馆里不按类别找书,硬翻每一页。

调整的时候,第一步是减少数据扫描范围,把“select *”换成具体需要的字段,比如只保留用户ID、订单金额、下单时间,这样数据量直接砍了一半,然后加上分区条件“where dt between '2024-01-01' and '2024-03-31'”,让hive只扫描这三个月的分区,不用翻以前的老数据,这一步就像给图书馆装了导航,直接定位到目标区域。

还有个坑是join顺序,有人觉得join谁在前谁在后都一样,其实大错特错,hive默认是小表驱动大表,要是把大表放前面,就像用大卡车拉小石子,费油又慢,我把订单表(大表)和用户标签表(小表)的位置换了下,让小表先加载到内存,再和大表匹配,查询时间又缩短了15分钟,现在那个查询稳定在10分钟左右,老板再也不用催了。

hive的优化里存储格式选择有哪些讲究

hive的数据存储格式就像给文件选“压缩包”,选对了能省空间还跑得快,选错了就是给自己挖坑,我刚接触hive时,图方便用了默认的TextFile格式,结果一个50G的表占了快100G磁盘,查询起来像蜗牛爬,后来才知道,存储格式里藏着大学问。

hive的优化有哪些实用方法,如何提升查询效率

Orc和Parquet是现在最常用的两种格式,各有各的脾气,Orc就像精密的收纳盒,数据按列存储,还自带索引和压缩,特别适合查询少量列的场景,我之前处理一个用户行为表,每天有2000万条记录,用TextFile时查“用户点击次数”要扫描全表,换成Orc后,因为只需要“用户ID”和“点击数”两列,它直接定位到这两列的数据块,速度快了3倍,磁盘空间也从80G压到了20G。

Parquet则像灵活的拼图,支持更复杂的嵌套数据结构,比如存JSON格式的数据就很合适,有次帮游戏公司处理玩家日志,日志里有“装备列表”“任务进度”这些嵌套字段,用Orc存会报错,换成Parquet后不仅能存,查询时还能直接按嵌套字段过滤,where 装备列表.武器 = ' sword'”,比以前拆表存方便多了,不过要注意,不管选哪种格式,最好配上Snappy压缩,压缩率高还不怎么影响速度,比Gzip省不少解压时间。

hive的优化参数调优该从哪里入手

hive的参数就像汽车的仪表盘,调对了能让引擎跑得更欢,刚开始用hive时,我以为默认参数就行,结果跑个大查询经常“卡壳”,不是内存不够就是任务超时,后来跟着老司机学了几招,才知道参数调优是“对症下药”。

最常用的是mapreduce参数,比如map数和reduce数,不是越多越好,有次跑一个100G的表关联,默认启动了500个map,结果每个map处理的数据太少,像500个人搬一堆沙子,互相抢资源还效率低,后来把map数调到100(通过set mapreduce.job.maps=100),每个map处理1G数据,速度反而快了20%,reduce数也是同理,一般按“每个reduce处理1-2G数据”来算,比如200G数据就设100-200个reduce,太多了会生成一堆小文件,后续查询更麻烦。

还有内存参数也很关键,hive跑任务时,map和reduce阶段都需要内存,要是给少了就会OOM(内存溢出),我之前遇到过一个任务,reduce阶段总失败,日志里全是“Java heap space”,查了下,默认reduce内存才1G,而我处理的数据有大量字符串拼接,内存不够用,把参数调成set mapreduce.reduce.memory.mb=4096(4G),再设置JVM堆内存set mapreduce.reduce.java.opts=-Xmx3072m(堆内存比总内存小一些,留缓冲),任务果然顺利跑完了,不过参数不是一成不变的,得根据数据量和服务器配置灵活调整,就像给不同体重的人配不同尺码的衣服,合身才舒服。

hive的数据倾斜问题怎么解决

数据倾斜简直是hive用户的“噩梦”——大部分任务都跑完了,就剩一两个reduce卡着不动,进度条停在99%能急死人,我去年帮一个做社交的公司处理数据时,就遇到过这种情况:他们要统计每个用户的互动次数,结果“匿名用户”这个key占了总数据的30%,所有数据都往一个reduce里跑,那台机器CPU直接飙到100%,跑了3小时还没出结果。

解决数据倾斜,首先得找到倾斜的key,可以通过hive的日志看reduce的输入数据量,哪个reduce处理的数据特别多,对应的key就是“罪魁祸首”,像“匿名用户”这种情况,属于“热点key”,解决办法有两种:一是打散key,在key后面加随机数,匿名用户_1”“匿名用户_2”,让数据分到多个reduce,处理完再合并结果;二是单独处理热点key,把“匿名用户”的数据挑出来单独计算,其他正常数据正常关联,最后把结果 union 起来,我当时用了第二种方法,匿名用户的数据单独跑,20分钟就搞定了,整体任务时间从3小时缩到了40分钟。

还有一种倾斜是null值倾斜,比如某个字段有大量null值,join的时候这些null会被分到同一个reduce,这时候可以把null值替换成随机字符串,null_${rand()}”,让它们分散到不同reduce,我之前处理用户表和订单表关联,用户表的“邮箱”字段有100万条null值,用这个方法处理后,倾斜的reduce从原来的1个变成了20个,每个处理5万条,一下子就跑完了,数据倾斜就像堵车,找到堵点,要么分流要么绕道,总能通。

hive的分区分桶策略对优化有什么帮助

分区和分桶就像给数据建“档案柜”,让hive能快速定位到需要的数据,不用翻箱倒柜,我刚用hive时,把所有数据都堆在一个表里,查询的时候不管要哪年的数据,都得全表扫描,慢得像蜗牛,后来学了分区分桶,才知道这才是提升查询速度的“王道”。

分区就像按“时间”“地区”分类放文件,比如电商的订单数据,可以按“日期(dt)”分区,每天一个分区;再按“地区(region)”子分区,每个地区一个文件夹,这样查“2024年3月北京的订单”,hive直接去dt=2024-03-01到2024-03-31的北京子分区找数据,不用扫其他日期和地区的,我之前帮一个物流公司做报表,没分区时查一个月的数据要2小时,按日期分区后,5分钟就出结果了,不过分区也不能太多,比如按“分钟”分区,一年就有50多万个分区,hive元数据管理会变慢,反而得不偿失。

分桶则是把大文件拆成小文件,就像把一沓纸分成几摞,找的时候不用搬整沓,分桶是按某个字段的哈希值分的,比如按“用户ID”分10个桶,每个桶里的用户ID哈希值固定,查询时可以指定桶号,直接定位到那个桶,有次我处理用户行为数据,表有100G,分10个桶后,查某个用户的行为,只需要扫10G数据,速度快了10倍,而且分桶表还支持抽样查询,select * from user_behavior tablesample(bucket 1 out of 10 on user_id)”,直接取1/10的数据,做数据分析时特别方便,分区是“粗分类”,分桶是“细分类”,两者结合用,数据查询效率能上天。

hive的优化和其他大数据工具对比优势在哪

现在大数据工具那么多,spark、presto、flink都能查数据,为啥还要费劲优化hive?其实hive有它独特的“看家本领”,不是其他工具能随便替代的,我之前在项目里对比过hive和spark SQL,发现hive在某些场景下优势特别明显。

hive的优化有哪些实用方法,如何提升查询效率

SQL兼容性,hive支持几乎所有标准SQL语法,连复杂的窗口函数、子查询都能完美运行,学过MySQL的人上手就能用,而spark SQL虽然也支持SQL,但有些高级语法比如“lateral view explode”用起来不如hive顺畅,我有次用spark SQL处理嵌套数组,写了半天没跑通,换成hive一句就搞定了,对习惯SQL的人来说,hive就像用惯了的筷子,顺手。

生态成熟度,hive在大数据生态里混了十几年,和hdfs、yarn、hbase这些工具都是“老熟人”,集成起来特别方便,比如hive可以直接读取hbase里的数据,也能把结果存到hdfs供其他工具调用,而presto虽然查询快,但生态没那么全,想把结果存到hbase还得写额外的代码,我之前帮一个金融公司搭数据平台,选hive做数据仓库的核心,就是看中它能和其他工具无缝衔接,省了不少集成的功夫。

稳定性,hive毕竟是老牌工具,经过了大量企业的考验,bug少,运行稳定,spark虽然快,但复杂查询时偶尔会有内存泄漏的问题,我之前用spark跑一个多表关联的查询,跑着跑着就内存溢出了,换成hive优化后,虽然慢了10分钟,但稳如老狗,从来没掉过链子,稳定有时候比速度更重要,毕竟数据出问题可是大事。

hive的优化实际案例分享

说了那么多理论,不如看个真实案例,去年我帮一个做生鲜电商的客户优化hive,他们的数据仓库里有个“商品销量分析表”,每天跑一次,用来统计每个商品的日销量、周销量、月销量,之前跑一次要2小时,经常赶不上早上的业务会,我去看了下,发现问题还真不少。

第一步先看表结构,他们用的是TextFile格式,没分区也没分桶,8000万条数据堆在一个表里,我先把表改成Orc格式,配上Snappy压缩,数据量从50G压到了12G,磁盘空间省了一大半,然后按“日期(dt)”分区,每天一个分区,这样查询某天的数据时,不用扫全表。

接着看SQL语句,原来的SQL用了“select 商品ID, sum(销量) as 日销量, sum(销量) over(partition by 商品ID order by dt rows between 6 preceding and current row) as 周销量...”,窗口函数写得没问题,但“sum(销量)”重复计算了两次,我把“sum(销量)”用子查询先算出来,再在外面用窗口函数,避免重复扫描数据,这一步让计算量少了30%。

最后处理数据倾斜,发现“未知商品”这个key占了总销量的20%,导致一个reduce卡壳,我把“未知商品”的数据单独拎出来,用“group by 商品ID”单独计算,其他商品正常算,最后用“union all”合并结果,这一下,那个卡壳的reduce终于动起来了。

一顿操作下来,原来2小时的任务,现在40分钟就跑完了,客户业务会再也不用担心数据没出来了,老板还给我涨了工资,说这优化比招两个数据工程师都管用,所以啊,hive优化不是纸上谈兵,实实在在能解决问题。

常见问题解答

hive优化最常用的方法有哪些啊?

hive优化最常用的方法可多啦!比如写SQL的时候别用“select *”,只选需要的字段,再加上分区条件,就像从冰箱里拿东西只开需要的抽屉,还有存储格式换成Orc或Parquet,压缩用Snappy,比原来的TextFile省空间又跑得快,数据倾斜也很常见,遇到热点key就打散它,或者把Null值换成随机数,让数据别挤在一个reduce里,我上次帮同学优化作业,就用了这些方法,查询时间从15分钟变成3分钟,老师都夸我厉害呢!

怎么判断hive有没有数据倾斜呀?

判断数据倾斜其实不难!你可以看hive的任务日志,里面会显示每个reduce处理的数据量,要是某个reduce处理的数据比别人多好多倍,比如其他reduce都是1G,就它是10G,那肯定倾斜了,或者看任务进度,大部分reduce都跑完了,就一两个卡在99%不动,那也是倾斜没跑了,我之前跑一个订单表关联,有个reduce进度一直停在99%,查日志发现“匿名用户”这个key占了30%的数据,后来把这个key单独处理就好了,超简单的!

hive存储格式选orc还是parquet好呀?

orc和parquet各有各的好,得看你存啥数据!orc就像那种带分隔格的文具盒,每列数据单独放,查少量列的时候特别快,比如只查“商品价格”“销量”这种,orc嗖嗖的,parquet呢,像能装各种形状东西的收纳盒,支持嵌套数据,比如存JSON里的数组、对象,parquet能直接存,查的时候还能按嵌套字段过滤,我上次存游戏玩家的装备数据,里面有“武器列表”“技能列表”这种嵌套字段,用orc存报错,换成parquet就没问题啦,你根据自己的数据类型选就行!

hive参数调优哪些最关键呀?

hive参数调优有几个关键的,记好啦!第一个是map和reduce的数量,map数别太多,每个map处理1-2G数据就行,不然像一堆人抢活干;reduce数按“数据量/2G”算,比如200G数据就设100个reduce,第二个是内存,map和reduce的内存不够就会OOM,一般map给2-4G,reduce给4-8G,JVM堆内存设成总内存的70%左右,第三个是“hive.auto.convert.join”,设成true能自动把小表转成map join,跑起来更快,我上次调一个大查询,把reduce内存从2G调到6G,一下就不卡了,超有用!

hive优化和spark优化有啥区别呀?

hive和spark优化区别还挺大的!hive是用mapreduce跑任务,优化主要靠调mapreduce参数、SQL和存储格式,它胜在稳定和SQL兼容性好