zoukankan      html  css  js  c++  java
  • Hive SQL优化

    1. join时将大表放后,小表放在前

    正确的说法:把重复关联键少的表放在join前面做关联可以提高join的效率,实际操作中也没法看什么重复连接键多少,因此一般都是小表在前了,表越少,重复的连接键总量就越少。

       因此通常需要将小表放前面,或者标记哪张表是大表:/*streamtable(table_name) */

    https://blog.csdn.net/qq_26442553/article/details/80865014?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduend~default-3-80865014.nonecase&utm_term=hive%20%E5%B0%8F%E8%A1%A8%E5%9C%A8%E5%89%8D%E7%9A%84%E5%8E%9F%E7%90%86&spm=1000.2123.3001.4430

    2. 多表join时,使用相同的连接键

      当对3个或者更多个表进行join连接时,如果每个on子句都使用相同的连接键的话,那么只会产生一个MapReduce job。因为,连接键一样,直接所有的map阶段的key就相同,只需要将所有表的key,按照hash分区,在reduce阶段聚合就行了,最后生成的结果就是总的结果。再者,reduce阶段的作用就是对相同的key进行操作的。若不一样,只能生成几个mapreduce分别处理。

    3. 尽量尽早地过滤数据,查询时也要注意数据过率,避免全表扫描

      减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段

    列处理:在 SELECT 中,只拿需要的列,如果有,尽量使用分区过滤,少用 SELECT *。

    行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面,那么就会先全表关联,之后再过滤。

    SELECT a.id
    
    FROM lxw1234_a a
    
    left outer join t_lxw1234_partitioned b
    
    ON (a.id = b.url);
    
    WHERE b.day = ‘2015-05-10′

    正确的写法是写在ON后面:

    SELECT a.id
    
    FROM lxw1234_a a
    
    left outer join t_lxw1234_partitioned b
    
    ON (a.id = b.url AND b.day = ‘2015-05-10′);

    或者直接写成子查询:

    SELECT a.id
    
    FROM lxw1234_a a
    
    left outer join (SELECT url FROM t_lxw1234_partitioned WHERE day = ‘2015-05-10′) b
    
    ON (a.id = b.url)

    4. 尽量原子化操作

      尽量避免一个SQL包含复杂逻辑,可以使用中间表来完成复杂的逻辑

    5. MapJoin避免数据倾斜

      如果不指定 MapJoin 或者不符合 MapJoin 的条件,那么 Hive 解析器会将 Join 操作转换成 Common Join,即:在 Reduce 阶段完成 join。容易发生数据倾斜。可以用 MapJoin 把小表全部加载到内存在 map 端进行 join,避免 reducer 处理。

    6. 并行执行

      hive会将一个查询转化为一个或多个阶段,包括:MapReduce阶段、抽样阶段、合并阶段、limit阶段等。默认情况下,一次只执行一个阶段。 不过,如果某些阶段不是互相依赖,是可以并行执行的。

      set hive.exec.parallel=true,可以开启并发执行。

       set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。

      会比较耗系统资源

    7、调整mapper和reducer的个数

    (1)map阶段优化:

      map个数的主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(默认128M,不可自定义)。

      举例: a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数

          b) 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数 即,如果文件大于块大小(128m),那么会拆分,如果小                           于 块大小,则把该文件当成一个块。

      map执行时间:map任务启动和初始化的时间+逻辑处理的时间。

           是不是 map 数越多越好?答案是否定的。如果一个任务有很多小文件(远远小于块大小 128m),则每个小文件也会被当做一个块,用一个 map 任务来完成,而一个 map 任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的 map 数是受限的。

           是不是保证每个 map 处理接近 128m 的文件块,就高枕无忧了?答案也是不一定。比如有一个 127m 的文件,正常会用一个 map 去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果 map 处理的逻辑比较复杂,用一个 map任务去做,肯定也比较耗时。

      针对上面的问题,我们需要采取两种方式来解决:即减少 map 数和增加 map 数;

    1)减少map数

      若有大量小文件(小于128M),会产生多个map,处理方法是:

      set mapred.max.split.size=100000000;

      set mapred.min.split.size.per.node=100000000;

      set mapred.min.split.size.per.rack=100000000;

      -- 前面三个参数确定合并文件块的大小,大于文件块大于128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的)进行合并

      set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 执行前进行小文件合并

    2)增加map数

      当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。

       set mapred.reduce.tasks=?

    (2)reduce阶段优化:

      Reduce 个数并不是越多越好?

      过多的启动和初始化 Reduce 也会消耗时间和资源;

      另外,有多少个 Reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;在设置 Reduce 个数的时候也需要考虑这两个原则:处理大数据量利用合适的 Reduce数;使单个 Reduce 任务处理数据量大小要合适;

      调整方式:

      -- set mapred.reduce.tasks=?

      -- set hive.exec.reducers.bytes.per.reducer = ?

      一般根据输入文件的总大小,用它的estimation函数来自动计算reduce的个数:reduce个数 = InputFileSize / bytes per reducer

    // 输出合并小文件

    SET hive.merge.mapfiles = true; -- 默认 true,在 map-only 任务结束时合并小文件
    SET hive.merge.mapredfiles = true; -- 默认 false,在 map-reduce 任务结束时合并小文件
    SET hive.merge.size.per.task = 268435456; -- 默认 256M
    SET hive.merge.smallfiles.avgsize = 16777216; -- 当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge

    8、采用 分区 技术

      在查询时候指定分区,可以避免全表扫描,其实就是到指定的分区文件下去查找想要的数据,这样就提升了效率。

    9、采用 分桶 技术

      分桶是对分区的进一步的划分。分桶将整个数据内容按照某列属性值的hash值进行区分,如要按照name属性分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶。如取模结果为0的数据记录存放到一个文件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件。

      提升Join查询的效率,若两个表都在连接的字段上进行了分桶,那么在join的时候可以使用 Map 端连接 (Map-side join)高效的实现。比如Join 操作。对于Join 操作两个表有一个相同的列,如果对这两个表都进行了分桶操作。那么将保存相同列值的桶进行Join 操作就可以,可以大大减少Join 数据量。

      分区和分桶:https://www.cnblogs.com/guoyu1/p/12123088.html

    参考博客:https://www.cnblogs.com/1130136248wlxk/articles/5517666.html

     

  • 相关阅读:
    Spring Web Flow 简介
    LeetCode:按序打印【1114】
    Java基础教程:多线程基础(5)——倒计时器(CountDownLatch)
    React:快速上手(8)——前后端分离的跨域访问与会话保持
    SpringBoot学习笔记:自定义拦截器
    Java进阶教程:垃圾回收
    SpringMVC:学习笔记(12)——ThreadLocal实现会话共享
    Node.js学习笔记(4):Yarn简明教程
    Docker:学习笔记(1)——核心概念及Ubuntu安装
    Java基础教程:内部类
  • 原文地址:https://www.cnblogs.com/guoyu1/p/12347235.html
Copyright © 2011-2022 走看看