zoukankan      html  css  js  c++  java
  • Hive高级(2):优化(2) 表的优化

    1 小表大表 Join(MapJOIN)

    将 key 相对分散,并且数据量小的表放在 join 的左边,可以使用 map join 让小的维度表先进内存。在 map 端完成 join。
    实际测试发现:新版的 hive 已经对小表 JOIN 大表和大表 JOIN 小表进行了优化。小表放在左边和右边已经没有区别。
    案例实操
    1)需求介绍
    测试大表 JOIN 小表和小表 JOIN 大表的效率
    2)开启 MapJoin 参数设置
    (1)设置自动选择 Mapjoin
    set hive.auto.convert.join = true; 默认为 true
    (2)大表小表的阈值设置(默认 25M 以下认为是小表):
    set hive.mapjoin.smalltable.filesize = 25000000;
    3)MapJoin 工作机制
    4)建大表、小表和 JOIN 后表的语句 
    // 创建大表
    create table bigtable(id bigint, t bigint, uid string, keyword string, 
    url_rank int, click_num int, click_url string) row format delimited 
    fields terminated by '	';
    
    // 创建小表
    create table smalltable(id bigint, t bigint, uid string, keyword string, 
    url_rank int, click_num int, click_url string) row format delimited 
    fields terminated by '	';
    
    // 创建 join 后表的语句
    create table jointable(id bigint, t bigint, uid string, keyword string, 
    url_rank int, click_num int, click_url string) row format delimited 
    fields terminated by '	';
    5)分别向大表和小表中导入数据 
    hive (default)> load data local inpath '/opt/module/data/bigtable' into 
    table bigtable;
    hive (default)>load data local inpath '/opt/module/data/smalltable' into 
    table smalltable;
    6)小表 JOIN 大表语句
    insert overwrite table jointable
    select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
    from smalltable s
    join bigtable b
    on b.id = s.id;
    7)大表 JOIN 小表语句 
    insert overwrite table jointable
    select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
    from bigtable b
    join smalltable s
    on s.id = b.id;

    2 大表 Join 大表

    1)空 KEY 过滤
    有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下,
    这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为空,操作如下:
    案例实操
    (1)配置历史服务器
    配置 mapred-site.xml 
    <property>
    <name>mapreduce.jobhistory.address</name>
    <value>hadoop102:10020</value>
    </property>
    <property>
     <name>mapreduce.jobhistory.webapp.address</name>
     <value>hadoop102:19888</value>
    </property>
    启动历史服务器
    sbin/mr-jobhistory-daemon.sh start historyserver
    查看 jobhistory
    http://hadoop102:19888/jobhistory
    (2)创建原始数据空 id 表
    // 创建空 id 表
    create table nullidtable(id bigint, t bigint, uid string, keyword string, 
    url_rank int, click_num int, click_url string) row format delimited 
    fields terminated by '	';
    (3)分别加载原始数据和空 id 数据到对应表中
    hive (default)> load data local inpath '/opt/module/data/nullid' into
    table nullidtable;
    (4)测试不过滤空 id
    hive (default)> insert overwrite table jointable select n.* from
    nullidtable n left join bigtable o on n.id = o.id;
    (5)测试过滤空 id
    hive (default)> insert overwrite table jointable select n.* from (select
    * from nullidtable where id is not null) n left join bigtable o on n.id =
    o.id; 
    2)空 key 转换
    有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在
    join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地
    分不到不同的 reducer 上。例如:
    案例实操:
    不随机分布空 null 值:
    (1)设置 5 个 reduce 个数
    set mapreduce.job.reduces = 5;
    (2)JOIN 两张表
    insert overwrite table jointable
    select n.* from nullidtable n left join bigtable b on n.id = b.id;
    结果:如下图所示,可以看出来,出现了数据倾斜,某些 reducer 的资源消耗远大于其他 reducer。
    随机分布空 null 值
    (1)设置 5 个 reduce 个数
    set mapreduce.job.reduces = 5;
    (2)JOIN 两张表
    insert overwrite table jointable
    select n.* from nullidtable n full join bigtable o on 
    nvl(n.id,rand()) = o.id;
    结果:如下图所示,可以看出来,消除了数据倾斜,负载均衡 reducer 的资源消耗
    3)SMB(Sort Merge Bucket join)
    (1)创建第二张大表 
    create table bigtable2(
     id bigint,
     t bigint,
     uid string,
     keyword string,
     url_rank int,
     click_num int,
     click_url string)
    row format delimited fields terminated by '	';
    load data local inpath '/opt/module/data/bigtable' into table bigtable2;
    测试大表直接 JOIN 
    insert overwrite table jointable
    select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
    from bigtable s
    join bigtable2 b
    on b.id = s.id;
    (2)创建分通表 1,桶的个数不要超过可用 CPU 的核数 
    create table bigtable_buck1(
     id bigint,
     t bigint,
     uid string,
     keyword string,
     url_rank int,
     click_num int,
     click_url string)
    clustered by(id) 
    sorted by(id)
    into 6 buckets
    row format delimited fields terminated by '	';
    load data local inpath '/opt/module/data/bigtable' into table 
    bigtable_buck1;
    (3)创建分通表 2,桶的个数不要超过可用 CPU 的核数
     
    create table bigtable_buck2(
     id bigint,
     t bigint,
     uid string,
     keyword string,
     url_rank int,
     click_num int,
     click_url string)
    clustered by(id)
    sorted by(id) 
    into 6 buckets
    row format delimited fields terminated by '	';
    load data local inpath '/opt/module/data/bigtable' into table 
    bigtable_buck2;
    (4)设置参数 
    set hive.optimize.bucketmapjoin = true;
    set hive.optimize.bucketmapjoin.sortedmerge = true;
    set 
    hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
    (5)测试
    insert overwrite table jointable
    select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
    from bigtable_buck1 s
    join bigtable_buck2 b
    on b.id = s.id;

    3 Group By

    默认情况下,Map 阶段同一 Key 数据分发给一个 reduce,当一个 key 数据过大时就倾斜了。 
    并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果。
    1)开启 Map 端聚合参数设置
    (1)是否在 Map 端进行聚合,默认为 True
    set hive.map.aggr = true
    (2)在 Map 端进行聚合操作的条目数目
    set hive.groupby.mapaggr.checkinterval = 100000
    (3)有数据倾斜的时候进行负载均衡(默认是 false)
    set hive.groupby.skewindata = true
    当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果
    是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证
    相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
    hive (default)> select deptno from emp group by deptno;
    Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 23.68 sec HDFS Read: 
    19987 HDFS Write: 9 SUCCESS
    Total MapReduce CPU Time Spent: 23 seconds 680 msec
    OK
    deptno
    10
    20
    30
    优化以后 
     
    hive (default)> set hive.groupby.skewindata = true;
    hive (default)> select deptno from emp group by deptno;
    Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 28.53 sec HDFS Read: 
    18209 HDFS Write: 534 SUCCESS
    Stage-Stage-2: Map: 1 Reduce: 5 Cumulative CPU: 38.32 sec HDFS Read: 
    15014 HDFS Write: 9 SUCCESS
    Total MapReduce CPU Time Spent: 1 minutes 6 seconds 850 msec
    OK
    deptno
    10
    20
    30

    4 Count(Distinct) 去重统计

      数据量小的时候无所谓,数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,
    一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题.
    1)案例实操
    (1)创建一张大表
    hive (default)> create table bigtable(id bigint, time bigint, uid string, 
    keyword
    string, url_rank int, click_num int, click_url string) row format 
    delimited
    fields terminated by '	';
    (2)加载数据 
    hive (default)> load data local inpath '/opt/module/data/bigtable' into table bigtable;
    (3)设置 5 个 reduce 个数
    set mapreduce.job.reduces = 5;
    (4)执行去重 id 查询 
    hive (default)> select count(distinct id) from bigtable;
    Stage-Stage-1: Map: 1 Reduce: 1 Cumulative CPU: 7.12 sec HDFS Read: 
    120741990 HDFS Write: 7 SUCCESS
    Total MapReduce CPU Time Spent: 7 seconds 120 msec
    OK
    c0
    100001
    Time taken: 23.607 seconds, Fetched: 1 row(s)
    (5)采用 GROUP by 去重 id
    hive (default)> select count(id) from (select id from bigtable group by 
    id) a;
    Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 17.53 sec HDFS Read: 
    120752703 HDFS Write: 580 SUCCESS
    Stage-Stage-2: Map: 1 Reduce: 1 Cumulative CPU: 4.29 sec2 HDFS Read: 
    9409 HDFS Write: 7 SUCCESS
    Total MapReduce CPU Time Spent: 21 seconds 820 msec
    OK
    _c0
    100001
    Time taken: 50.795 seconds, Fetched: 1 row(s)
    虽然会多用一个 Job 来完成,但在数据量大的情况下,这个绝对是值得的。

    5 笛卡尔积

    尽量避免笛卡尔积,join 的时候不加 on 条件,或者无效的 on 条件,Hive 只能使用 1 个reducer 来完成笛卡尔积。

    6 行列过滤

    列处理:在 SELECT 中,只拿需要的列,如果有分区,尽量使用分区过滤,少用 SELECT *。
    行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面,
    那么就会先全表关联,之后再过滤,比如:
    案例实操: 
    1)测试先关联两张表,再用 where 条件过滤 
    hive (default)> select o.id from bigtable b
    join bigtable o on o.id = b.id
    where o.id <= 10;
    Time taken: 34.406 seconds, Fetched: 100 row(s)
    2)通过子查询后,再关联表
    hive (default)> select b.id from bigtable b
    join (select id from bigtable where id <= 10) o on b.id = o.id;
    Time taken: 30.058 seconds, Fetched: 100 row(s) 

    7 分区

    详见 7.1 章。

    8 分桶

    详见 7.2 章。
     
     
     
     

    本文来自博客园,作者:秋华,转载请注明原文链接:https://www.cnblogs.com/qiu-hua/p/13373974.html

  • 相关阅读:
    SQL语法分类
    SQL语法入门
    数据库的基本对象
    数据库基础
    数据库概述
    设计模式之备忘录模式
    设计模式之State模式
    设计模式之装饰模式
    简单工厂模式
    初识C#设计模式
  • 原文地址:https://www.cnblogs.com/qiu-hua/p/13373974.html
Copyright © 2011-2022 走看看