Hive核心优化

数据采样

        分桶表概述:

                分桶就是分文件, 在创建表的时候, 指定分桶字段, 并设置分多少个桶, 在添加数据的时候, hive会根据设置分桶字段, 将数据划分到N个桶(文件)中, 默认情况采用HASH分桶方案 , 分多少个桶, 取决于建表的时候, 设置分桶数量, 分了多少个桶最终翻译的MR也就会运行多少个reduce程序(HIVE的分桶本质上就是MR的分区操作)

        如何向桶表添加数据

        创建一个分桶表

create table 表名(
    字段 类型,
    ....
)
clustered by(分桶字段) [sorted by (字段 [asc | desc])] into N buckets   
-- 定义分桶表核心语句
row format......

        添加数据

insert into|overwrite + select 将数据添加到桶表
现有一个文本文件数据, 需要加载到分桶表,如何解决呢? 
   第一步: 基于桶表创建一张临时表, 此表和桶表保持相同字段, 唯一区别, 当前这个表不是一个桶表
   第二步: 将数据先加载到这个临时表中
   第三步: 基于临时表, 使用 insert into|overwrite + select 将数据添加到桶表
注:在CDH中默认开启了一个参数, 是禁止采用load data方式向桶表添加数据的:  set hive.strict.checks.bucketing = true;
        桶表的作用

                1.进行数据采样工作

                    当表的数据量比较庞大的时候, 在编写SQL语句后, 需要首先测试 SQL是否可以正常的执行,  需要在表中执行查询操作, 由于表数据量比较庞大, 在测试一条SQL的时候整个运行的时间比较久, 为了提升测试效率, 可以整个表抽样出一部分的数据, 进行测试
                    校验数据的可行性(质量校验)
                    进行统计分析的时候, 并不需要统计出具体的指标, 可能统计的都是一些相对性指标, 比如说一些比率(合格率)问题, 此时可以通过采样处理

                2.提升查询的效率

                    可以减少JOIN次数, 从而提升效率

        如何采样
采样函数: tablesample(bucket x out of y [on column])
使用位置:紧紧跟在表名的后面, 如果表名有别名, 必须放置别名的前面
说明:
	x: 从第几个桶开始进行采样; 
	y: 抽样比例; column: 分桶的字段, 可以省略
注意:
	1. x 不能大于 y; 
	2. y 必须是表的分桶数量的倍数或者因子
案例:
	1) 假设 A表有10个桶, 请分析, 下面的采样函数, 会将那些桶抽取出来呢?
tablesample(bucket 2 out of 5 on xxx)
共计抽取2个桶, 分别是 1号桶和6号桶
	2) 假设 A 表有20个桶, 请分析, 下面的抽样函数, 会将那些桶抽取出来呢?
tablesample(bucket 4 out of 4 on xxx)
共计抽取5个桶, 分别是 3,7,11,15,19
tablesample(bucket 8 out of 40 on xxx)
抽取二分之一个桶, 分别是7号桶二分之一

join 优化

        Map Join

                Map Join: 每一个mapTask在读取数据的时候, 每读取一条数据, 就会和内存中班级表数据进行匹配, 如果能匹配的上, 将匹配上数据合并在一起, 输出即可

                好处: 将原有reduce join 问题全部都可以解决
                弊端: 
                    1. 比较消耗内存
                    2. 要求整个 Join 中, 必须的都有一个小表, 否则无法放入到内存中
仅适用于: 小表 join 大表 | 大表 join 小表   

        配置:

set hive.auto.convert.join=true; 
-- 开启 map join的支持  默认值为True
set hive.auto.convert.join.noconditionaltask.size=20971520; 
-- 设置 小表数据量的最大阈值: 默认值为 20971520(20M)
        Bucket Map Join

                适用场景: 中型表  和 大表  join: 
                使用条件: 
                    1- Join两个表必须是分桶表
                    2- 开启 Bucket Map Join 支持:  set hive.optimize.bucketmapjoin = true;
                    3- 一个表的分桶数量是另一个表的分桶数量的整倍数
                    4- 分桶列 必须 是 join的ON条件的列
                    5- 必须建立在Map Join场景中(中型表是小表的3倍, 此时分至少3个桶)

        SMB Join

                适用场景: 大表 和 大表 join
                使用条件: 
                    1- 两个表必须都是分桶表
                    2- 开启 SMB Join 支持:  

​
set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;

                   3- 两个表的分桶的数量是一致的
                   4- 分桶列 必须是 join的 on条件的列, 同时必须保证按照分桶列进行排序操作

-- 开启强制排序
set hive.enforce.sorting=true;
 -- 在建分桶表使用: 必须使用sorted by()

                   5-  应用在Bucket Map Join 场景中

-- 开启 bucket map join
set hive.optimize.bucketmapjoin = true; 

                   6- 必须开启HIVE自动尝试使用SMB 方案: 

set hive.optimize.bucketmapjoin.sortedmerge = true;

HIVE的索引

        Row Group Index索引
条件: 
    1) 要求表的存储类型为ORC存储格式
    2) 在创建表的时候, 必须开启 row group index 索引支持
        'orc.create.index'='true'
    3) 在插入数据的时候, 必须保证需求进行索引列, 按序插入数据
适用于: 数值类型的, 并且对数值类型进行 >  <  = 操作
思路: 
    插入数据到ORC表后, 会自动进行划分为多个script片段, 每个片段内部, 会保存着每个字段的最小, 最大值, 这样, 当执行查询 > < = 的条件筛选操作的时候, 根据最小最大值锁定相关的script片段, 从而减少数据扫描量, 提升效率
操作: 
    CREATE TABLE lxw1234_orc2 (字段列表 ....) stored AS ORC 
    TBLPROPERTIES ( 
      'orc.compress'='SNAPPY', 
      -- 开启行组索引 
      'orc.create.index'='true' 
    )
    插入数据的时候, 需要保证数据有序的
    insert overwrite table lxw1234_orc2
    SELECT  id, pcid FROM lxw1234_text 
    -- 插入的数据保持排序(可以使用全局排序, 也可以使用局部排序, 只需要保证一定有序即可, 建议使用局部排序 插入数据效率高一些, 因为全局排序只有一个reduce) 
    DISTRIBUTE BY id sort BY id;
使用: 
    set hive.optimize.index.filter=true; 
    SELECT COUNT(1) FROM lxw1234_orc1 WHERE id >= 1382 AND id <= 1399;
        Bloom Fliter Index索引
条件: 
    1) 要求表的存储类型为 ORC存储方案
    2) 在建表的饿时候, 必须设置为那些列构建布隆索引
    3) 仅能适合于等值过滤查询操作
思路: 
    在开启布隆过滤索引后, 可以针对某个列, 或者某几列来建立索引, 构建索引后, 会将这一列的数据的值存储在对应script片段的索引信息中, 这样当进行 等值查询的时候, 首先会到每一个script片段的索引中, 判断是否有这个值, 如果没有, 直接跳过script, 从而减少数据扫描量, 提升效率
操作:  
    CREATE TABLE lxw1234_orc2 (字段列表....)
    stored AS ORC 
    TBLPROPERTIES ( 
      'orc.compress'='SNAPPY', 
      -- 开启 行组索引 (可选的, 支持全部都打开, 也可以仅开启一个)
      'orc.create.index'='true', 
      -- pcid字段开启BloomFilter索引 
      'orc.bloom.filter.columns'='pcid,字段2,字段3...'
    )
    插入数据: 没有要求, 当然如果开启行组索引, 可以将需要使用行组索引的字段, 进行有序插入即可
使用:
    SET hive.optimize.index.filter=true; 
    SELECT COUNT(1) FROM lxw1234_orc1 WHERE id >= 0 AND id <= 1000 AND pcid IN ('0005E26F0DCCDB56F9041C','A');

数据倾斜

        Join数据倾斜

        解决方案一:

                可以通过 Map Join Bucket Map Join 以及 SMB Join 解决,但是这种操作是存在使用条件的, 如果无法满足这些条件, 无法使用 这种处理方案

        解决方案二:

                将那些产生倾斜的key和对应v2的数据, 从当前这个MR中移出去, 单独找一个MR来处理即可, 处理后, 和之前的MR进行汇总结果即可,但是需要找到倾斜的key,两种解决方案: 运行期处理方案编译期处理方案

运行期处理方案

-- 实操:
set hive.optimize.skewjoin=true; 
-- 开启运行期处理倾斜参数
set hive.skewjoin.key=100000; 
-- 阈值, 此参数在实际生产环境中, 需要调整在一个合理的值(否则极易导致大量的key都是倾斜的)
-- 适用于: 并不清楚哪个key容易产生倾斜, 此时交由系统来动态检测

编译期处理方案

-- 实操:
set hive.optimize.skewjoin.compiletime=true; 
-- 开启编译期处理倾斜参数
CREATE TABLE list_bucket_single (key STRING, value STRING)
-- 倾斜的字段和需要拆分的key值
SKEWED BY (key) ON (1,5,6)
-- 为倾斜值创建子目录单独存放
[STORED AS DIRECTORIES]
-- 适用于: 提前知道那些key存在倾斜
        union all 优化方案

                不管是运行期 还是编译期的join倾斜解决, 最终都会运行多个MR, 将多个MR结果通过union all 进行汇总,union all也是需要单独一个MR来处理
                解决方案:
                    让每一个MR在运行完成后, 直接将结果输出到目的地即可, 默认 是各个MR将结果输出临时目录, 通过 union all 合并到最终目的地
        开启此参数即可:

set hive.optimize.union.remove=true;
        group by 数据倾斜

                倾斜发生后, 出现的问题, 程序迟迟无法结束, 或者说翻译的MR中reduceTask有多个, 大部分的reduceTask都执行完成了, 只有其中一个或者几个没有执行完成, 此时认为发生了数据倾斜

                方案一: 基于MR的 combiner(规约, 提前聚合) 减少数据达到reduce数量, 从而减轻倾斜问题

                只需要在HIVE中开启combiner提前聚合配置参数即可:

set hive.map.aggr=true;

                方案二: 负载均衡的解决方案(需要运行两个MR来处理)

                只需要开启负载均衡的HIVE参数配置即可:

set hive.groupby.skewindata=true;

你可能感兴趣的:(hive,hadoop,数据仓库)