hive优化

数据压缩

判断一种压缩协议好与坏的标准: 压缩后文件占比, 解压速度, 压缩速度.

Hive的底层是MR程序, 所以Hive的压缩本质上还是MR的压缩, 它(MR程序)支持GZip, Bzip2, Lzo, Snappy(推荐使用: 因为更均衡)等协议.

数据压缩分为两项, 即: Map端压缩 和 Reduce端压缩.

  • Map端压缩的目的:
    ​ 降低Reduce端拉取的数据量, 减少传输, 提高效率.
  • Reduce端压缩的目的:
    ​ 降低写入磁盘的数据量, 减小结果文件的大小, 提高磁盘利用率.
存储方式

Hive表的存储格式分为 行存储 和 列存储两种, 其中:
​ 行存储主要有两种方式: TextFile(默认的), SequenceFile
​ 列存储主要有两种方式: Orc(推荐, 更均衡), Parquet(Spark中用的较多)

行存储

优点: select * from … 方式, 查询数据, 效率较高.

缺点:

  • 数据密集度低, 磁盘利用率低.
  • select 列1, 列2…方式, 效率低.
列存储

优点:

  • 数据密集度较高, 磁盘利用率高.
  • select 列1, 列2…方式, 效率高.

缺点: select * 方式效率相对较低, 但是实际开发中, 这种写法几乎不用.

细节:

  • 实际开发中, 如果 存储格式 和 压缩协议 你也不知道用谁了, 推荐使用: Orc + Snappy.
  • 存储的底层是用 二进制 的形式来存储数据的.
  • ods层一般使用 orc + zlib 或者 orc + snappy
  • 其他层主要使用 orc + snappy
Fetch抓取

我们知道Hive的底层要转MR任务来执行, 而MR程序的计算速度是非常慢的, 如果执行的是简单的HiveSQL, 没必要转MR程序, 直接执行即可.

大白话, Fetch抓取的意思是: HiveSQL 底层能不转MR, 就不转MR, 而是直接执行.
哪些SQL不会转MR程序的呢?

  • select * 全表扫描.
  • select 列1, 列2 字段扫描.
  • limit 分页查询.
  • 一些简单的SQL语句.
通过 set hive.fetch.task.conversion=值;     的方式, 可以设置本地抓取模式.
    more(默认值):  上述四项都不走MR.
    minimal: 全表扫描, 列扫描, 分页查询不走MR.
    none: 所有HiveSQL都走MR.
本地模式

如果HiveSQL非要转MR程序, 能在本地执行, 就尽量不要交给Yarn来调度, 因为可能会涉及到跨域(跨机器)传输, 降低效率.

join优化
join优化有3种情况, 即:
        小表join大表:
            1. 开启Map端join, 在Map端(内存中)对数据做合并, 降低Reduce端拉取的数据量, 一方面提高传输效率, 另一方面可以防止出现数据倾斜.
            2. 其实join优化你开与不开, 本质没有太大的区别, 因为Hive为了提高查询效率, 已经设置了, 自动join优化.
        大表join大表:
            假设有A表(100W条数据, id列50W是空),   B表(60W条数据, id列40W空), 如果此时两张表根据 id列做关联查询, 会有大量的空值.
            原始写法:
                select * from A inner join B on A.id = B.id;        -- 弊端是: id列有大量的空值, 无意义的操作较多.
            1. 空值过滤.
                select * from A inner join (select * from B where id is not null) B on A.id = B.id;   -- 弊端: 会过滤掉大量的数据, 可能也会把有效的数据过滤掉
            2. 空值转换.
                # 2.1 不随机分布, 固定值.
                select * from A inner join (
                    select 列1, 列2.., case when id is null then 10 end as id from B
                ) B on A.id = B.id;   -- 虽然能解决, 但是null值过多, 会导致10过多, 将来出现数据倾斜的概率较大.

                # 2.2 随机分布, 可变值..
                select * from A inner join (
                    select 列1, 列2.., case when id is null then concat(值, rand()) end as id from B
                ) B on A.id = B.id;
        分桶表 join 分桶表:
            前提:
                1. 两张表都是分桶表.
                2. 某表的分桶数量 是另外表 分桶数量的 偶数倍.
            结论:
                表join连接查询的时候, 可以用 分桶字段替代 关联字段, 即:
                原始SQL:
                    select * from A join B on A.id = B.id;
                优化后SQL:
                    select * from A join B on A.分桶字段 = B.分桶字段;
join的三种方式
map-side join(map join)

​ map Join的主要思想就是,当关联的两个表是一个小表和一个大表的时候,我们把比较小的表直接放到内存中去,然后再对比较大的表进行map操作,join就发生在map操作的时候,每当扫描大表中的一行数据,就要去查看小表的数据,哪条与之相符,继而进行连接。

​ 这样的join并不会涉及reduce操作,自然没有shuffle,减少了数据通过网络传输造成的高成本和高延迟,因为Join 是在 map 端完成的,所以又叫做map join.

reduce-side join(Common join)

在map阶段,map函数同时读取两个文件File1和File2,为了区分两种来源的key/value数据对,对每条数据打一个标签(tag)接下来通过shuffle 操作,就保证了相同key 的数据落在了同一个 reducer 中,然后在这个 reducer 中完成相应的 join 逻辑.

sort merge bucket join(SMB join)

桶可以提高join 的效率,桶可以保证相同key 的数据都分在了一个桶里,这个时候我们关联的时候不需要去扫描整个表的数据,只需要扫描对应桶里的数据(因为key 相同的一定在一个桶里),smb的设计是为了解决大表和大表之间的join的,核心思想就是大表化成小表,然后map side join 解决是典型的分而治之的思想。

这里有一点要注意,那就是数据落在那个桶里不止和key 的值相关,还和桶的个数相关,因为我们是根据 key 的哈希值然后对桶的个数取余数获得一个值,然后根据这个值将数据放到对应的桶里去的,所以一般情况下我们要求不止是两个分桶表的分桶字段是相等的,还要求桶的个数是倍数关系(相等也是可以的)

开启方式
-- map Join
set hive.auto.convert.join.noconditionaltask.size=512000000 ;
set hive.auto.convert.join=true;

-- bucket map join
1) 开启bucket map join功能:  set hive.optimize.bucketmapjoin = true;
2) 一个表的bucket数是另一个表bucket数的整数倍
3) bucket列 == join列
4) 必须是应用在map join的场景中

-- smb
1) 保证join的表必须是桶表: 
set hive.enforce.bucketing=true; --写入数据强制分桶
2) 在建表的时候, 必须设置分桶排序字段 而且需要保证  分桶字段 = join的字段 = 排序的字段
create table test_smb_2(mid string,age_id string)
CLUSTERED BY(mid) SORTED BY(mid) INTO 500 BUCKETS;

set hive.enforce.sorting=true; -- 开启强制排序

3) 两个分桶表的分桶的数量必须一致
4) 必须建立bucket map join的基础上
    set hive.optimize.bucketmapjoin = true;
5) 必须开启 SMB join
    set hive.auto.convert.sortmerge.join=true;
    set hive.auto.convert.sortmerge.join.noconditionaltask=true;
6) 必须开启 自动尝试使用SMB
    set hive.optimize.bucketmapjoin.sortedmerge = true; 
sql优化
列裁剪

能写 select 列1, 列2 就不要写 select *

分区裁剪

查询时, 如果是分区表, 记得写 where 分组字段

先分组再统计

如果数据量大, 容易出错, 可以改成 先分组, 后统计, 虽然会转2个MR, 执行速度慢了, 但是数据量大的情况下, 也可以成功执行.

避免笛卡尔积

笛卡尔积一般无意义, 且数据join次数多, 因此要避免.

group by 数据倾斜

描述: 分配给ReduceTask端的数据不均衡导致的问题. 例如: 1个ReduceTask处理100W条数据, 另1个ReduceTask处理100条数据.
​ 解决方案:
​ 手动开启负载均衡, 程序的底层会转两个MR程序来执行该任务, 第1个MR程序负责把倾斜的数据随机打散, 交给不同的ReduceTask来处理.
​ 第1个MR程序的(Reduce端结果) 作为 第2个MR程序的Map段数据源, 然后由第2个MR的Reduce负责合并数据.

动态分区

手动调大动态分区数, 默认动态分区上限是1000, 如果HQL分区数量超过它, 会报错, 我们调大分区数即可.

小细节: 动态分区的时候, 可以关闭严格模式, 因为严格模式要求: 动态分区时至少有1个静态分区.

调整MR任务数
调整MapTask任务数
  • 1个切片 = 1个MapTask任务 = 1个分好区, 排好序, 规好约的文件.
  • 小切片大小(默认: 128MB) = 增多MapTask任务数, 增大切片大小 = 减少MapTask任务数.
调整ReduceTask任务数
  • 1个分区 = 1个ReduceTask任务 = 1个结果文件
  • 动设置分区数, 即可修改ReduceTask的任务数量.
并行执行

默认情况下, HiveSQL只会执行1个阶段, 如果多阶段之间依赖度不高, 我们可以开启并行执行机制.

并行执行机制, 默认并行度是 8, 我们可以调大一些.

严格模式

这个严格模式指的是 禁用低效的SQL, 即: 如果SQL比较低效, 压根儿不让你执行.

低效sql例如:

  • select *… 全表扫描
  • order by的时候没有加 limit
  • 笛卡尔积.
jvm重用

Hive2.X已开启, 无需设置, Hive2.X以前Container容器用一次就释放了, 开启JVM重用, 可以重复利用这些Container资源容器.

explain执行计划

在HQL前加 explain执行计划, 查看SQL的执行分几个阶段, 阶段越少, 执行速度越快.

推测执行
  • 实际开发, 禁用它, 类似于木桶效应.
  • 假设HQL转了3个MapReduce任务, 其中前两个任务执行速度都较快, 但是第三个任务执行速度太慢了, 会拖慢整个MR程序的执行进度.
  • 此时程序会开启1个新的任务, 负责和那个慢的任务做同样的事儿, 采用谁先执行完, 用谁的结果. 无意义, 因为已经很慢了, 开启新任务后会更慢.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值