1.Hive的参数配置问题?
Hive的参数配置有三种方式, 分别是:
1. 修改配置文件.
直接去 /export/server/hive/conf 文件中, 修改 hive-env.sh, hive-site.xml文件即可.
2. 命令行配置.
nohup hive --service hiveserver2 --hiveconf 参数名=参数值 &
3. 参数配置.
set mapreduce.job.reduces = 3;
优先级, 从高到低分别是:
参数配置 > 命令行配置 > 配置文件
作用范围, 从高到低分别是:
配置文件 > 命令行配置 > 参数配置
2.Hive调优详解
1. 数据压缩.
解释:
就是使用压缩协议, 对Hive表数据进行压缩.
区分压缩协议快与慢, 可以参考3个维度:
压缩后文件占比, 压缩速度(写), 解压速度(读)
我们以后常用的压缩协议:
Snappy 压缩后文件不大(压缩比相对较高), 解压, 压缩速度快.
Zlib 压缩比高, 解压和压缩速度稍慢.
MR程序中, 也可以对Map端的数据 和 Reduce端的数据分别做压缩:
Map段压缩: 降低Reduce端拉取数据的数量, 减少传输, 提高查询效率.
Reduce端压缩: 降低结果文件的大小, 提高磁盘(资源)使用率.
2. 存储方式.
解释:
指的就是Hive表的底层, 用 行存储 还是 列存储.
存储方式主要有如下两种:
行存储:
细节: 行存储又分为 TextFile(默认) 和 SequenceFile 两种方式.
好处: select * 方式, 效率高.
弊端: select 列方式, 效率相对较低. 数据密集度比较低, 占用大量存储空间.
列存储: 如果表是列存储的, 你去看它的HDFS文件内容, 看不到(乱码), 因为底层是二进制方式存的, 所以才会节省存储空间.
细节: 列存储又分为 Orc 和 Parquet 两种方式.
好处: select 列方式, 效率高. 数据密集度较高, 占用少量存储空间.
弊端: select * 方式, 效率相对较低.
问题: 会不会出现1个Block块中, 全部是某个列的数据?
答案: 如果是行存储, 绝无可能, 如果是列存储, 有可能.
3. Fetch抓取
概述/解释:
HiveSQL能直接执行, 就不要转MR程序, 然后在执行, 它有几种模式可以选择, 具体如下.
设置格式:
set hive.fetch.task.conversion = 模式名;
常用模式:
more: 默认模式, 全表查询, 查询指定列, 简单查询, limit分页查询不走MR, 其它转MR程序.
minimal: 全表查询, 查询指定列, limit分页查询不走MR, 其它转MR程序.
none: 全部都转MR程序.
4. 本地模式
如果HiveSQL非要转MR程序, 能在本地直接执行, 就不要交由Yarn来调度.
5. join优化
概述/解释:
主要有 大表 join 大表, 小表 join 大表, 桶表 join 桶表三种情况.
思路为:
1. 如果是 小表 join 大表, 则开启Map段join, 能在Map端做合并, 就不要到Reduce端做合并.
2. 如果是 大表 join 大表, 则有 空值过滤 和 空值转换两种思路.
select * from a join b on a.id = b.id; -- 假设 B表(100W条, 30W空)
select * from a join (select * from b where id is not null) b on a.id = b.id; 空值过滤.
select * from a join (select 列1,列2..., if(id is null, 10, id) id from b) b on a.id = b.id; 空值转换, 固定值, 可能存在数据倾斜情况.
select * from a join (select 列1,列2..., if(id is null, concat(10, rand()), id) id from b) b on a.id = b.id; 空值转换, 随机填充.
3. 桶表 join 桶表, 且表A的桶的数量, 是表B的桶的数量的整数倍, 则可以用 分桶字段 替代 关联字段, 即: on a.id = b.id => on a.分桶字段 = b.分桶字段;
6. SQL常规优化
1. 列裁剪. 能写 select 列1, 列2... 不要写 select * ...
2. 分区裁剪. 分区表查询时, 尽量写分区字段, 即: select ... from 表名 where 分区字段=...;
3. group by数据倾斜.
解释:
由于数据源的问题, 某个分区(标记)的数据, 可能远远大于另外一些分区(标记的数据), 就会出现数据倾斜. 例如: 0分区: 1W, 1分区: 97W, 2分区: 2W.
解决方案:
手动开启 负载均衡, 即: set hive.groupby.skewindata=true; 程序会自动开启两个MR任务处理该数据,
第1个MR负责将数据随机打散(避免倾斜), 进行处理, 获取到结果. 第1个MR程序的Reduce结果 作为 第2个MR程序的 MapTask任务数据源.
由第2个MR程序对数据做最终合并即可.
4. count()计数的时候, 如果数据量比较大, 尽量用group by 结合 count一起用.
select count(distinct id) from表名; -- 转1个MR, 数据量大的时候, 可能失败.
select count(id) from (select id from 表名 group by id) a; -- 转2个MR, 效率相对较低, 但是大数据量情况下, 也能计算.
5. 避免出现笛卡尔积的情况.
就是你在join查询的时候, 尽量写关联条件, 例如: select * from a, b on 关联条件;
7. 动态分区.
关闭严格模式, 因为严格模式要求, 动态分区时, 只要要指定1个静态分区.
且我们可以设置分区的数量, 避免因为分区数量较小, 但是文件分区较多的情况下, HiveSQL出错的问题.
8. 调整MapReduce任务数.
MapTask任务数:
默认情况下, 1个切片 = 128MB = 1个MapTask任务, 我们可以通过设置切片大小, 从而调整MapTask任务数.
例如: 小文件较多的时候, 我们就用归档包, 降低MapTask任务数...
ReduceTask任务数:
默认情况下, 1个分区 = 1个ReduceTask任务 = 1个最终结果文件, 如果要调整ReduceTask数量, 就手动调整 分区数量.
9. 并行执行.
如果1个HiveSQL转换成了多个阶段, 且各个阶段之间的依赖度不高的情况下, 就可以考虑让这些阶段 并行执行. 可以提高执行效率.
10. 严格模式
这个严格模式不是动态分区的严格模式, 这个严格模式是: 禁用低效的SQL.
低效SQL如下:
1. 分区表, 查询的时候, 没有写分区字段.
2. order by语句 必须要结合 limit一起用.
3. 禁用笛卡尔积的操作.
11. JVM重用
默认情况下, Container资源容器用一次就释放了, 频繁的创建和销毁非常消耗资源, 实现JVM重用, 就是实现Container资源容器重用.
12. 推测执行.
类似于: 木桶效应, 当1个MR程序的多个Task任务并行执行时, 如果某个Task任务执行速度较慢, 会严重拖慢整个程序的执行进度.
Hive会找出那个执行最慢的Task任务, 然后创建1个新的任务, 和它执行一模一样的计算, 然后采用谁先计算完, 就用谁的结果.
实际开发中, 一般禁用.
13. explain执行计划.
格式:
explain HiveSQL语句; 可以查看HiveSQL划分成了多少个阶段, 越少越好.
3.HiveSQL调优总结:
1.调硬件.
包括但不限于: CPU, 内存, 磁盘, 因为Hive依赖: Hadoop, MySQL, Java, Linux, 所以这些优化都会影响HiveSQL执行效率.
2.开启或者增大某些配置.
例如: Fetch抓取, 并行度机制, 动态分区数, 负载均衡(解决: Group by数据倾斜), 严格模式(禁用低效SQL)......
3.关闭或者减小某些配置.
例如: 推测执行, 动态分区的严格模式, MapTask任务数(当小文件过多, 1个文件 至少 = 1个MapTask, 可以通过 归档包 解决)
4.减少IO传输.
例如: 存储方式(行存储, 列存储), 压缩方式(zlib, snappy), join优化.
记住:存储方式, 压缩方式, join优化, 数据倾斜