一、计算资源配置 计算环境为 Hive on MR。计算资源的调整主要包括 Yarn 和 MR。 1.1、Yarn资源配置 修改$HADOOP_HOME/etc/hadoop/yarn-site.xml文件。 需要调整的 Yarn 参数均与 CPU、内存等资源有关，核心配置参数如下。 （1）yarn.nodemanager.resource.memory-mb 该参数的含义是，一个 NodeManager 节点分配给 Container 使用的内存。该参数的配置，取决于 NodeManager 所在节点的总内存容量和该节点运行的其他服务的数量。 考虑上述因素，此处可将该参数设置为64G，如下： <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>65536</value> </property> （2）yarn.nodemanager.resource.cpu-vcores 该参数的含义是，一个 NodeManager 节点分配给 Container 使用的 CPU 核数。该参数的配置，同样取决于 NodeManager 所在节点的总 CPU 核数和该节点运行的其他服务。 考虑上述因素，此处可将该参数设置为16。 <property> <name>yarn.nodemanager.resource.cpu-vcores</name> <value>16</value> </property> （3）yarn.scheduler.maximum-allocation-mb 该参数的含义是，单个 Container 能够使用的最大内存。推荐配置如下： <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>16384</value> </property> （4）yarn.scheduler.minimum-allocation-mb 该参数的含义是，单个 Container 能够使用的最小内存，推荐配置如下： <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>512</value> </property> 1.2、MapReduce资源配置 MapReduce 资源配置主要包括 Map Task 的内存和 CPU核数，以及 Reduce Task 的内存和 CPU核数。核心配置参数如下： 1）mapreduce.map.memory.mb 该参数的含义是，单个 Map Task 申请的 container 容器内存大小，其默认值为1024。该值不能超出yarn.scheduler.maximum-allocation-mb和yarn.scheduler.minimum-allocation-mb规定的范围。 该参数需要根据不同的计算任务单独进行配置，在 hive 中，可直接使用如下方式为每个SQL语句单独进行配置： set mapreduce.map.memory.mb=2048; 2）mapreduce.map.cpu.vcores 该参数的含义是，单个 Map Task 申请的 container 容器 cpu核数，其默认值为1。该值一般无需调整。 3）mapreduce.reduce.memory.mb 该参数的含义是，单个 Reduce Task 申请的 container 容器内存大小，其默认值为 1024。该值同样不能超出yarn.scheduler.maximum-allocation-mb和yarn.scheduler.minimum-allocation-mb规定的范围。 该参数需要根据不同的计算任务单独进行配置，在hive中，可直接使用如下方式为每个SQL语句单独进行配置： set mapreduce.reduce.memory.mb=2048; 4）mapreduce.reduce.cpu.vcores 该参数的含义是，单个 Reduce Task 申请的 container 容器 cpu核数，其默认值为1。该值一般无需调整。 二、 测试用表 2.1、订单表(2000w条数据) 1）表结构 2）建表语句 hive (default)> drop table if exists order_detail; create table order_detail( id string comment '订单id', user_id string comment '用户id', product_id string comment '商品id', province_id string comment '省份id', create_time string comment '下单时间', product_num int comment '商品件数', total_amount decimal(16, 2) comment '下单金额' ) partitioned by (dt string) row format delimited fields terminated by '\t'; 3）数据装载 将 order_detail.txt 文件上传到 hadoop102 节点的 /opt/module/hive/datas/ 目录，并执行以下导入语句。 注：文件较大，请耐心等待。 hive (default)> load data local inpath '/opt/module/hive/datas/order_detail.txt' overwrite into table order_detail partition(dt='2020-06-14'); 2.2、支付表(600w条数据) 1）表结构 2）建表语句 hive (default)> drop table if exists payment_detail; create table payment_detail( id string comment '支付id', order_detail_id string comment '订单明细id', user_id string comment '用户id', payment_time string comment '支付时间', total_amount decimal(16, 2) comment '支付金额' ) partitioned by (dt string) row format delimited fields terminated by '\t'; 3）数据装载 将 payment_detail.tx t文件上传到 hadoop102 节点的 /opt/module/hive/datas/ 目录，并执行以下导入语句。 注：文件较大，请耐心等待。 hive (default)> load data local inpath '/opt/module/hive/datas/payment_detail.txt' overwrite into table payment_detail partition(dt='2020-06-14'); 2.3、商品信息表(100w条数据) 1）表结构 2）建表语句 hive (default)> drop table if exists product_info; create table product_info( id string comment '商品id', product_name string comment '商品名称', price decimal(16, 2) comment '价格', category_id string comment '分类id' ) row format delimited fields terminated by '\t'; 3）数据装载 将 product_info.txt 文件上传到 hadoop102 节点的 /opt/module/hive/datas/ 目录，并执行以下导入语句。 hive (default)> load data local inpath '/opt/module/hive/datas/product_info.txt' overwrite into table product_info; 2.4、省份信息表(34条数据) 1）表结构 2）建表语句 hive (default)> drop table if exists province_info; create table province_info( id string comment '省份id', province_name string comment '省份名称' ) row format delimited fields terminated by '\t'; 3）数据装载 将province_info.txt文件上传到hadoop102节点的/opt/module/hive/datas/目录，并执行以下导入语句。 hive (default)> load data local inpath '/opt/module/hive/datas/province_info.txt' overwrite into table province_info; 三、 Explain查看执行计划 3.1、Explain执行计划概述 Explain 呈现的执行计划，由一系列 Stage 组成，这一系列 Stage 具有依赖关系，每个Stage对应一个 MapReduce Job，或者一个文件系统操作等。 若某个 Stage 对应的一个 MapReduce Job，其 Map 端和 Reduce 端的计算逻辑分别由 Map Operator Tree 和 Reduce Operator Tree 进行描述，Operator Tree由一系列的Operator组成，一个Operator代表在Map或Reduce阶段的一个单一的逻辑操作，例如TableScan Operator，Select Operator，Join Operator等。 下图是由一个执行计划绘制而成： 常见的Operator及其作用如下： TableScan：表扫描操作，通常map端第一个操作肯定是表扫描操作 Select Operator：选取操作 Group By Operator：分组聚合操作 Reduce Output Operator：输出到 reduce 操作 Filter Operator：过滤操作 Join Operator：join 操作 File Output Operator：文件输出操作 Fetch Operator：客户端获取数据操作 3.2、基本语法 EXPLAIN [FORMATTED | EXTENDED | DEPENDENCY] query-sql 注：FORMATTED、EXTENDED、DEPENDENCY关键字为可选项，各自作用如下。 FORMATTED：将执行计划以JSON字符串的形式输出 EXTENDED：输出执行计划中的额外信息，通常是读写的文件名等信息 DEPENDENCY：输出执行计划读取的表及分区 3.3、案例实操 1）查看下面这条语句的执行计划 hive (default)> explain select user_id, count(*) from order_detail group by user_id; 2）执行计划如下图 四、HQL语法优化之分组聚合优化 4.1、优化说明 Hive 中未经优化的分组聚合，是通过一个 MapReduce Job 实现的。Map 端负责读取数据，并按照分组字段分区，通过Shuffle，将数据发往 Reduce 端，各组数据在 Reduce 端完成最终的聚合运算。 Hive 对分组聚合的优化主要围绕着减少 Shuffle 数据量进行，具体做法是 map-side 聚合。所谓 map-side 聚合，就是在 map 端维护一个 hash table，利用其完成部分的聚合，然后将部分聚合的结果，按照分组字段分区，发送至 reduce 端，完成最终的聚合。map-side 聚合能有效减少 shuffle 的数据量，提高分组聚合运算的效率。 map-side 聚合相关的参数如下： --启用map-side聚合 set hive.map.aggr=true; --用于检测源表数据是否适合进行map-side聚合。检测的方法是：先对若干条数据进行map-side聚合，若聚合后的条数和聚合前的条数比值小于该值，则认为该表适合进行map-side聚合；否则，认为该表数据不适合进行map-side聚合，后续数据便不再进行map-side聚合。 set hive.map.aggr.hash.min.reduction=0.5; --用于检测源表是否适合map-side聚合的条数。 set hive.groupby.mapaggr.checkinterval=100000; --map-side聚合所用的hash table，占用map task堆内存的最大比例，若超出该值，则会对hash table进行一次flush。 set hive.map.aggr.hash.force.flush.memory.threshold=0.9; 4.2、优化案例 1）示例SQL hive (default)> select product_id, count(*) from order_detail group by product_id; 2）优化前 未经优化的分组聚合，执行计划如下图所示： 3）优化思路 可以考虑开启 map-side 聚合，配置以下参数： --启用map-side聚合，默认是true set hive.map.aggr=true; --用于检测源表数据是否适合进行map-side聚合。检测的方法是：先对若干条数据进行map-side聚合，若聚合后的条数和聚合前的条数比值小于该值，则认为该表适合进行map-side聚合；否则，认为该表数据不适合进行map-side聚合，后续数据便不再进行map-side聚合。 set hive.map.aggr.hash.min.reduction=0.5; --用于检测源表是否适合map-side聚合的条数。 set hive.groupby.mapaggr.checkinterval=100000; --map-side聚合所用的hash table，占用map task堆内存的最大比例，若超出该值，则会对hash table进行一次flush。 set hive.map.aggr.hash.force.flush.memory.threshold=0.9; 优化后的执行计划如图所示： 五、HQL语法优化之Join优化 5.1、Join算法概述 Hive 拥有多种 join 算法，包括 Common Join，Map Join，Bucket Map Join，Sort Merge Buckt Map Join 等，下面对每种 join 算法做简要说明： 5.1.1、Common Join Common Join 是 Hive 中最稳定的 join 算法，其通过一个 MapReduce Job 完成一个 join 操作。Map 端负责读取 join 操作所需表的数据，并按照关联字段进行分区，通过 Shuffle，将其发送到 Reduce 端，相同 key 的数据在 Reduce 端完成最终的 Join 操作。如下图所示： 需要注意的是，sql 语句中的 join 操作和执行计划中的 Common Join 任务并非一对一的关系，一个 sql 语句中的相邻的且关联字段相同的多个 join 操作可以合并为一个 Common Join 任务。 例如： hive (default)> select a.val, b.val, c.val from a join b on (a.key = b.key1) join c on (c.key = b.key1) 上述 sql 语句中两个 join 操作的关联字段均为b表的 key1 字段，则该语句中的两个 join 操作可由一个 Common Join 任务实现，也就是可通过一个 Map Reduce 任务实现。 hive (default)> select a.val, b.val, c.val from a join b on (a.key = b.key1) join c on (c.key = b.key2) 上述sql语句中的两个 join 操作关联字段各不相同，则该语句的两个 join 操作需要各自通过一个 Common Join 任务实现，也就是通过两个 Map Reduce 任务实现。 5.1.2、Map Join Map Join 算法可以通过两个只有 map 阶段的 Job 完成一个 join 操作。其适用场景为大表 join 小表。若某 join 操作满足要求，则第一个 Job 会读取小表数据，将其制作为 hash table，并上传至 Hadoop 分布式缓存（本质上是上传至HDFS）。第二个 Job 会先从分布式缓存中读取小表数据，并缓存在 Map Task 的内存中，然后扫描大表数据，这样在 map 端即可完成关联操作。如下图所示： 5.1.3、Bucket Map Join Bucket Map Join 是对 Map Join 算法的改进，其打破了 Map Join 只适用于大表 join 小表的限制，可用于大表 join 大表的场景。 Bucket Map Join 的核心思想是：若能保证参与 join 的表均为分桶表，且关联字段为分桶字段，且其中一张表的分桶数量是另外一张表分桶数量的整数倍，就能保证参与 join 的两张表的分桶之间具有明确的关联关系，所以就可以在两表的分桶间进行 Map Join 操作了。这样一来，第二个 Job 的 Map 端就无需再缓存小表的全表数据了，而只需缓存其所需的分桶即可。其原理如图所示： 5.1.4、Sort Merge Bucket Map Join Sort Merge Bucket Map Join（简称SMB Map Join）基于 Bucket Map Join。SMB Map Join 要求，参与 join 的表均为分桶表，且需保证分桶内的数据是有序的，且分桶字段、排序字段和关联字段为相同字段，且其中一张表的分桶数量是另外一张表分桶数量的整数倍。 SMB Map Join 同 Bucket Join 一样，同样是利用两表各分桶之间的关联关系，在分桶之间进行join操作，不同的是，分桶之间的 join 操作的实现原理。Bucket Map Join，两个分桶之间的 join 实现原理为 Hash Join 算法；而 SMB Map Join，两个分桶之间的 join 实现原理为 Sort Merge Join算法。 Hash Join 和 Sort Merge Join 均为关系型数据库中常见的Join实现算法。Hash Join 的原理相对简单，就是对参与 join 的一张表构建 hash table，然后扫描另外一张表，然后进行逐行匹配。Sort Merge Join 需要在两张按照关联字段排好序的表中进行，其原理如图所示： Hive中 的 SMB Map Join 就是对两个分桶的数据按照上述思路进行 Join 操作。可以看出，SMB Map Join 与 Bucket Map Join 相比，在进行Join操作时，Map端是无需对整个 Bucket 构建 hash table，也无需在 Map 端缓存整个 Bucket 数据的，每个 Mapper 只需按顺序逐个 key 读取两个分桶的数据进行 join 即可。 5.2、Map Join 5.2.1、优化说明 Map Join 有两种触发方式，一种是用户在 SQL 语句中增加 hint 提示，另外一种是 Hive 优化器根据参与 join 表的数据量大小，自动触发。 1）Hint提示 用户可通过如下方式，指定通过 map join 算法，并且ta将作为 map join 中的小表。这种方式已经过时，不推荐使用。 hive (default)> select /*+ mapjoin(ta) */ ta.id, tb.id from table_a ta join table_b tb on ta.id=tb.id; 2）自动触发 Hive 在编译SQL语句阶段，起初所有的join操作均采用 Common Join 算法实现。 之后在物理优化阶段，Hive 会根据每个 Common Join 任务所需表的大小判断该 Common Join 任务是否能够转换为 Map Join 任务，若满足要求，便将 Common Join 任务自动转换为Map Join任务。 但有些 Common Join 任务所需的表大小，在 SQL 的编译阶段是未知的（例如对子查询进行 join 操作），所以这种 Common Join 任务是否能转换成 Map Join 任务在编译阶是无法确定的。 针对这种情况，Hive 会在编译阶段生成一个条件任务（Conditional Task），其下会包含一个计划列表，计划列表中包含转换后的 Map Join 任务以及原有的 Common Join 任务。最终具体采用哪个计划，是在运行时决定的。大致思路如下图所示： Map join 自动转换的具体判断逻辑如下图所示： 图中涉及到的参数如下： --启动Map Join自动转换 set hive.auto.convert.join=true; --一个 Common Join operator转为Map Join operator的判断条件,若该Common Join相关的表中,存在n-1张表的已知大小总和<=该值,则生成一个Map Join计划,此时可能存在多种n-1张表的组合均满足该条件,则hive会为每种满足条件的组合均生成一个Map Join计划,同时还会保留原有的Common Join计划作为后备(back up)计划,实际运行时,优先执行Map Join计划，若不能执行成功，则启动Common Join后备计划。 set hive.mapjoin.smalltable.filesize=250000; --开启无条件转Map Join set hive.auto.convert.join.noconditionaltask=true; --无条件转Map Join时的小表之和阈值,若一个Common Join operator相关的表中，存在n-1张表的大小总和<=该值,此时hive便不会再为每种n-1张表的组合均生成Map Join计划,同时也不会保留Common Join作为后备计划。而是只生成一个最优的Map Join计划。 set hive.auto.convert.join.noconditionaltask.size=10000000; 5.2.2、优化案例 1）示例SQL hive (default)> select * from order_detail od join product_info product on od.product_id = product.id join province_info province on od.province_id = province.id; 2）优化前 上述 SQL 语句共有三张表进行两次 join 操作，且两次join操作的关联字段不同。故优化前的执行计划应该包含两个 Common Join operator，也就是由两个 MapReduce 任务实现。执行计划如下图所示： 3）优化思路 经分析，参与 join 的三张表，数据量如下 表名 大小 order_detail 1176009934（约1122M） product_info 25285707（约24M） province_info 369（约0.36K） 注：可使用如下语句获取表/分区的大小信息 hive (default)> desc formatted table_name partition(partition_col='partition'); 三张表中，product_info 和 province_info 数据量较小，可考虑将其作为小表，进行 Map Join 优化。 根据前文 Common Join 任务转 Map Join 任务的判断逻辑图，可得出以下优化方案： 方案一： 启用 Map Join 自动转换。 hive (default)> set hive.auto.convert.join=true; 不使用无条件转 Map Join。 hive (default)> set hive.auto.convert.join.noconditionaltask=false; 调整hive.mapjoin.smalltable.filesize参数，使其大于等于product_info。 hive (default)> set hive.mapjoin.smalltable.filesize=25285707; 这样可保证将两个 Common Join operator 均可转为 Map Join operator，并保留 Common Join 作为后备计划，保证计算任务的稳定。调整完的执行计划如下图： 方案二： 启用 Map Join 自动转换。 hive (default)> set hive.auto.convert.join=true; 使用无条件转Map Join。 hive (default)> set hive.auto.convert.join.noconditionaltask=true; 调整hive.auto.convert.join.noconditionaltask.size参数，使其大于等于product_info和province_info之和。 hive (default)> set hive.auto.convert.join.noconditionaltask.size=25286076; 这样可直接将两个 Common Join operator 转为两个 Map Join operator，并且由于两个 Map Join operator 的小表大小之和小于等于hive.auto.convert.join.noconditionaltask.size，故两个 Map Join operator 任务可合并为同一个。这个方案计算效率最高，但需要的内存也是最多的。 调整完的执行计划如下图 方案三： 启用 Map Join 自动转换。 hive (default)> set hive.auto.convert.join=true; 使用无条件转 Map Join。 hive (default)> set hive.auto.convert.join.noconditionaltask=true; 调整hive.auto.convert.join.noconditionaltask.size参数，使其等于product_info。 hive (default)> set hive.auto.convert.join.noconditionaltask.size=25285707; 这样可直接将两个 Common Join operator 转为 Map Join operator，但不会将两个 Map Join 的任务合并。该方案计算效率比方案二低，但需要的内存也更少。 调整完的执行计划如下图： 5.3、Bucket Map Join 5.3.1、优化说明 Bucket Map Join 不支持自动转换，发须通过用户在 SQL 语句中提供如下 Hint 提示，并配置如下相关参数，方可使用。 1）Hint提示 hive (default)> select /*+ mapjoin(ta) */ ta.id, tb.id from table_a ta join table_b tb on ta.id=tb.id; 2）相关参数 --关闭cbo优化，cbo会导致hint信息被忽略 set hive.cbo.enable=false; --map join hint默认会被忽略(因为已经过时)，需将如下参数设置为false set hive.ignore.mapjoin.hint=false; --启用bucket map join优化功能 set hive.optimize.bucketmapjoin = true; 5.3.2、优化案例 1）示例SQL hive (default)> select * from( select * from order_detail where dt='2020-06-14' )od join( select * from payment_detail where dt='2020-06-14' )pd on od.id=pd.order_detail_id; 2）优化前 上述SQL语句共有两张表一次 join 操作，故优化前的执行计划应包含一个 Common Join 任务，通过一个 MapReduce Job 实现。执行计划如下图所示： 3）优化思路 经分析，参与join的两张表，数据量如下。 表名 大小 order_detail 1176009934（约1122M） payment_detail 334198480（约319M） 两张表都相对较大，若采用普通的 Map Join 算法，则Map端需要较多的内存来缓存数据，当然可以选择为 Map 段分配更多的内存，来保证任务运行成功。但是，Map端的内存不可能无上限的分配，所以当参与 Join 的表数据量均过大时，就可以考虑采用 Bucket Map Join 算法。下面演示如何使用 Bucket Map Join。 首先需要依据源表创建两个分桶表，order_detail 建议分 16 个 bucket，payment_detail 建议分8个bucket，注意分桶个数的倍数关系以及分桶字段。 --订单表 hive (default)> drop table if exists order_detail_bucketed; create table order_detail_bucketed( id string comment '订单id', user_id string comment '用户id', product_id string comment '商品id', province_id string comment '省份id', create_time string comment '下单时间', product_num int comment '商品件数', total_amount decimal(16, 2) comment '下单金额' ) clustered by (id) into 16 buckets row format delimited fields terminated by '\t'; --支付表 hive (default)> drop table if exists payment_detail_bucketed; create table payment_detail_bucketed( id string comment '支付id', order_detail_id string comment '订单明细id', user_id string comment '用户id', payment_time string comment '支付时间', total_amount decimal(16, 2) comment '支付金额' ) clustered by (order_detail_id) into 8 buckets row format delimited fields terminated by '\t'; 然后向两个分桶表导入数据。 --订单表 hive (default)> insert overwrite table order_detail_bucketed select id, user_id, product_id, province_id, create_time, product_num, total_amount from order_detail where dt='2020-06-14'; --分桶表 hive (default)> insert overwrite table payment_detail_bucketed select id, order_detail_id, user_id, payment_time, total_amount from payment_detail where dt='2020-06-14'; 然后设置以下参数： --关闭cbo优化，cbo会导致hint信息被忽略，需将如下参数修改为false set hive.cbo.enable=false; --map join hint默认会被忽略(因为已经过时)，需将如下参数修改为false set hive.ignore.mapjoin.hint=false; --启用bucket map join优化功能,默认不启用，需将如下参数修改为true set hive.optimize.bucketmapjoin = true; 最后在重写SQL语句，如下： hive (default)> select /*+ mapjoin(pd) */ * from order_detail_bucketed od join payment_detail_bucketed pd on od.id = pd.order_detail_id; 优化后的执行计划如图所示： 需要注意的是，Bucket Map Join的执行计划的基本信息和普通的Map Join无异，若想看到差异，可执行如下语句，查看执行计划的详细信息。详细执行计划中，如在Map Join Operator中看到 “BucketMapJoin: true”，则表明使用的Join算法为Bucket Map Join。 hive (default)> explain extended select /*+ mapjoin(pd) */ * from order_detail_bucketed od join payment_detail_bucketed pd on od.id = pd.order_detail_id; 5.4、Sort Merge Bucket Map Join 5.4.1、优化说明 Sort Merge Bucket Map Join 有两种触发方式，包括 Hint 提示和自动转换。Hint 提示已过时，不推荐使用。下面是自动转换的相关参数： --启动Sort Merge Bucket Map Join优化 set hive.optimize.bucketmapjoin.sortedmerge=true; --使用自动转换SMB Join set hive.auto.convert.sortmerge.join=true; 5.4.2 优化案例 1）示例SQL语句 hive (default)> select * from( select * from order_detail where dt='2020-06-14' )od join( select * from payment_detail where dt='2020-06-14' )pd on od.id=pd.order_detail_id; 2）优化前 上述SQL语句共有两张表一次 join 操作，故优化前的执行计划应包含一个 Common Join 任务，通过一个 MapReduce Job 实现。 3）优化思路 经分析，参与 join 的两张表，数据量如下 表名 大小 order_detail 1176009934（约1122M） payment_detail 334198480（约319M） 两张表都相对较大，除了可以考虑采用 Bucket Map Join 算法，还可以考虑 SMB Join。相较于 Bucket Map Join，SMB Map Join 对分桶大小是没有要求的。下面演示如何使用 SMB Map Join。 首先需要依据源表创建两个的有序的分桶表，order_detail 建议分 16 个 bucket，payment_detail 建议分 8 个 bucket,注意分桶个数的倍数关系以及分桶字段和排序字段。 --订单表 hive (default)> drop table if exists order_detail_sorted_bucketed; create table order_detail_sorted_bucketed( id string comment '订单id', user_id string comment '用户id', product_id string comment '商品id', province_id string comment '省份id', create_time string comment '下单时间', product_num int comment '商品件数', total_amount decimal(16, 2) comment '下单金额' ) clustered by (id) sorted by(id) into 16 buckets row format delimited fields terminated by '\t'; --支付表 hive (default)> drop table if exists payment_detail_sorted_bucketed; create table payment_detail_sorted_bucketed( id string comment '支付id', order_detail_id string comment '订单明细id', user_id string comment '用户id', payment_time string comment '支付时间', total_amount decimal(16, 2) comment '支付金额' ) clustered by (order_detail_id) sorted by(order_detail_id) into 8 buckets row format delimited fields terminated by '\t'; 然后向两个分桶表导入数据。 --订单表 hive (default)> insert overwrite table order_detail_sorted_bucketed select id, user_id, product_id, province_id, create_time, product_num, total_amount from order_detail where dt='2020-06-14'; --分桶表 hive (default)> insert overwrite table payment_detail_sorted_bucketed select id, order_detail_id, user_id, payment_time, total_amount from payment_detail where dt='2020-06-14'; 然后设置以下参数： --启动Sort Merge Bucket Map Join优化 set hive.optimize.bucketmapjoin.sortedmerge=true; --使用自动转换SMB Join set hive.auto.convert.sortmerge.join=true; 最后在重写SQL语句，如下： hive (default)> select * from order_detail_sorted_bucketed od join payment_detail_sorted_bucketed pd on od.id = pd.order_detail_id; 优化后的执行计如图所示： 六、HQL语法优化之数据倾斜 6.1、数据倾斜概述 数据倾斜问题，通常是指参与计算的数据分布不均，即某个 key 或者某些 key 的数据量远超其他key，导致在 shuffle 阶段，大量相同 key 的数据被发往同一个 Reduce，进而导致该Reduce所需的时间远超其他 Reduce，成为整个任务的瓶颈。 Hive 中的数据倾斜常出现在分组聚合和 join 操作的场景中，下面分别介绍在上述两种场景下的优化思路。 6.2、分组聚合导致的数据倾斜 6.2.1、优化说明 前文提到过，Hive 中未经优化的分组聚合，是通过一个 MapReduce Job 实现的。Map 端负责读取数据，并按照分组字段分区，通过 Shuffle，将数据发往 Reduce 端，各组数据在 Reduce 端完成最终的聚合运算。 如果 group by 分组字段的值分布不均，就可能导致大量相同的 key 进入同一 Reduce，从而导致数据倾斜问题。 由分组聚合导致的数据倾斜问题，有以下两种解决思路： 1）Map-Side聚合 开启 Map-Side 聚合后，数据会现在Map端完成部分聚合工作。这样一来即便原始数据是倾斜的，经过 Map 端的初步聚合后，发往Reduce的数据也就不再倾斜了。最佳状态下，Map-端聚合能完全屏蔽数据倾斜问题。 相关参数如下： --启用map-side聚合 set hive.map.aggr=true; --用于检测源表数据是否适合进行map-side聚合。检测的方法是：先对若干条数据进行map-side聚合，若聚合后的条数和聚合前的条数比值小于该值，则认为该表适合进行map-side聚合；否则，认为该表数据不适合进行map-side聚合，后续数据便不再进行map-side聚合。 set hive.map.aggr.hash.min.reduction=0.5; --用于检测源表是否适合map-side聚合的条数。 set hive.groupby.mapaggr.checkinterval=100000; --map-side聚合所用的hash table，占用map task堆内存的最大比例，若超出该值，则会对hash table进行一次flush。 set hive.map.aggr.hash.force.flush.memory.threshold=0.9; 2）Skew-GroupBy优化 Skew-GroupBy 的原理是启动两个 MR 任务，第一个 MR 按照随机数分区，将数据分散发送到 Reduce，完成部分聚合，第二个 MR 按照分组字段分区，完成最终聚合。 相关参数如下： --启用分组聚合数据倾斜优化 set hive.groupby.skewindata=true; 6.2.2、优化案例 1）示例SQL语句 hive (default)> select province_id, count(*) from order_detail group by province_id; 2）优化前 该表数据中的 province_id 字段是存在倾斜的，若不经过优化，通过观察任务的执行过程，是能够看出数据倾斜现象的。 需要注意的是，hive中的map-side聚合是默认开启的，若想看到数据倾斜的现象，需要先将hive.map.aggr参数设置为false。 3）优化思路 通过上述两种思路均可解决数据倾斜的问题。下面分别进行说明： （1）Map-Side聚合 设置如下参数 --启用map-side聚合 set hive.map.aggr=true; --关闭skew-groupby set hive.groupby.skewindata=false; 很明显可以看到开启 map-side 聚合后，reduce 数据不再倾斜。 （2）Skew-GroupBy 优化 设置如下参数 --启用skew-groupby set hive.groupby.skewindata=true; --关闭map-side聚合 set hive.map.aggr=false; 开启 Skew-GroupBy 优化后，可以很明显看到该 sql 执行在yarn上启动了两个 MR 任务，第一个 MR 打散数据，第二个 MR 按照打散后的数据进行分组聚合。 6.3、Join导致的数据倾斜 6.3.1、优化说明 前文提到过，未经优化的 join 操作，默认是使用 common join 算法，也就是通过一个 MapReduce Job 完成计算。Map 端负责读取 join 操作所需表的数据，并按照关联字段进行分区，通过 Shuffle，将其发送到 Reduce 端，相同 key 的数据在 Reduce端完成最终的 Join 操作。 如果关联字段的值分布不均，就可能导致大量相同的 key 进入同一 Reduce，从而导致数据倾斜问题。 由join导致的数据倾斜问题，有如下三种解决方案： 1）map join 使用 map join 算法，join 操作仅在 map 端就能完成，没有 shuffle 操作，没有 reduce 阶段，自然不会产生 reduce 端的数据倾斜。该方案适用于大表 join 小表时发生数据倾斜的场景。 相关参数如下： --启动Map Join自动转换 set hive.auto.convert.join=true; --一个Common Join operator转为Map Join operator的判断条件,若该Common Join相关的表中,存在n-1张表的大小总和<=该值,则生成一个Map Join计划,此时可能存在多种n-1张表的组合均满足该条件,则hive会为每种满足条件的组合均生成一个Map Join计划,同时还会保留原有的Common Join计划作为后备(back up)计划,实际运行时,优先执行Map Join计划，若不能执行成功，则启动Common Join后备计划。 set hive.mapjoin.smalltable.filesize=250000; --开启无条件转Map Join set hive.auto.convert.join.noconditionaltask=true; --无条件转Map Join时的小表之和阈值,若一个Common Join operator相关的表中，存在n-1张表的大小总和<=该值,此时hive便不会再为每种n-1张表的组合均生成Map Join计划,同时也不会保留Common Join作为后备计划。而是只生成一个最优的Map Join计划。 set hive.auto.convert.join.noconditionaltask.size=10000000; 2）skew join skew join 的原理是，为倾斜的大key单独启动一个 map join 任务进行计算，其余 key 进行正常的 common join。原理图如下： 相关参数如下： --启用skew join优化 set hive.optimize.skewjoin=true; --触发skew join的阈值，若某个key的行数超过该参数值，则触发 set hive.skewjoin.key=100000; 这种方案对参与 join 的源表大小没有要求，但是对两表中倾斜的 key 的数据量有要求，要求一张表中的倾斜 key 的数据量比较小（方便走mapjoin）。 3）调整SQL语句 若参与join的两表均为大表，其中一张表的数据是倾斜的，此时也可通过以下方式对SQL语句进行相应的调整。 假设原始SQL语句如下：A，B两表均为大表，且其中一张表的数据是倾斜的。 hive (default)> select * from A join B on A.id=B.id; 其join过程如下： 图中1001为倾斜的大key，可以看到，其被发往了同一个Reduce进行处理。 调整SQL语句如下： hive (default)> select * from( select --打散操作 concat(id,'_',cast(rand()*2 as int)) id, value from A )ta join( select --扩容操作 concat(id,'_',0) id, value from B union all select concat(id,'_',1) id, value from B )tb on ta.id=tb.id; 调整之后的SQL语句执行计划如下图所示： 6.3.2、优化案例 1）示例SQL语句 hive (default)> select * from order_detail od join province_info pi on od.province_id=pi.id; 2）优化前 order_detail 表中的 province_id 字段是存在倾斜的，若不经过优化，通过观察任务的执行过程，是能够看出数据倾斜现象的。 需要注意的是，hive中的map join自动转换是默认开启的，若想看到数据倾斜的现象，需要先将hive.auto.convert.join参数设置为false。 3）优化思路 上述两种优化思路均可解决该数据倾斜问题，下面分别进行说明： （1）map join 设置如下参数 --启用map join set hive.auto.convert.join=true; --关闭skew join set hive.optimize.skewjoin=false; 可以很明显看到开启map join以后，mr任务只有map阶段，没有reduce阶段，自然也就不会有数据倾斜发生。 （2）skew join 设置如下参数 --启动skew join set hive.optimize.skewjoin=true; --关闭map join set hive.auto.convert.join=false; 开启 skew join 后，使用 explain 可以很明显看到执行计划如下图所示，说明skew join生效，任务既有 common join，又有部分 key 走了 map join。 并且该 sql 在yarn上最终启动了两个mr任务，而且第二个任务只有 map 没有 reduce 阶段，说明第二个任务是对倾斜的 key 进行了map join。 七、HQL语法优化之任务并行度 7.1、优化说明 对于一个分布式的计算任务而言，设置一个合适的并行度十分重要。Hive的计算任务由MapReduce完成，故并行度的调整需要分为Map端和Reduce端。 7.1.1、Map端并行度 Map端的并行度，也就是Map的个数。是由输入文件的切片数决定的。一般情况下，Map端的并行度无需手动调整。 以下特殊情况可考虑调整map端并行度： 1）查询的表中存在大量小文件 按照 Hadoop 默认的切片策略，一个小文件会单独启动一个 map task 负责计算。若查询的表中存在大量小文件，则会启动大量map task，造成计算资源的浪费。这种情况下，可以使用 Hive 提供的CombineHiveInputFormat，多个小文件合并为一个切片，从而控制 map task 个数。相关参数如下： set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 2）map端有复杂的查询逻辑 若 SQL 语句中有正则替换、json 解析等复杂耗时的查询逻辑时，map端的计算会相对慢一些。若想加快计算速度，在计算资源充足的情况下，可考虑增大map端的并行度，令 map task 多一些，每 个map task 计算的数据少一些。相关参数如下： --一个切片的最大值 set mapreduce.input.fileinputformat.split.maxsize=256000000; 7.1.2、Reduce端并行度 Reduce 端的并行度，也就是 Reduce 个数。相对来说，更需要关注。Reduce 端的并行度，可由用户自己指定，也可由 Hive 自行根据该 MR Jo b输入的文件大小进行估算。 Reduce 端的并行度的相关参数如下： --指定Reduce端并行度，默认值为-1，表示用户未指定 set mapreduce.job.reduces; --Reduce端并行度最大值 set hive.exec.reducers.max; --单个Reduce Task计算的数据量，用于估算Reduce并行度 set hive.exec.reducers.bytes.per.reducer; Reduce 端并行度的确定逻辑如下： 若指定参数mapreduce.job.reduces的值为一个非负整数，则 Reduce 并行度为指定值。否则，Hive 自行估算 Reduce 并行度，估算逻辑如下： 假设Job输入的文件大小为totalInputBytes 参数hive.exec.reducers.bytes.per.reducer的值为bytesPerReducer。 参数hive.exec.reducers.max的值为maxReducers。 则Reduce端的并行度为： min⁡(ceil(totalInputBytes/bytesPerReducer),maxReducers) 根据上述描述，可以看出，Hive 自行估算 Reduce 并行度时，是以整个 MR Job 输入的文件大小作为依据的。因此，在某些情况下其估计的并行度很可能并不准确，此时就需要用户根据实际情况来指定 Reduce 并行度了。 7.2、优化案例 1）示例SQL语句 hive (default)> select province_id, count(*) from order_detail group by province_id; 2）优化前 上述 sql 语句，在不指定 Reduce 并行度时，Hive 自行估算并行度的逻辑如下： totalInputBytes= 1136009934 bytesPerReducer=256000000 maxReducers=1009 经计算，Reduce并行度为 numReducers=min(ceil(1136009934/256000000),1009)=5 3）优化思路 上述sql语句，在默认情况下，是会进行map-side聚合的，也就是Reduce端接收的数据，实际上是map端完成聚合之后的结果。观察任务的执行过程，会发现，每个map端输出的数据只有34条记录，共有5个map task。 八、HQL语法优化之小文件合并 8.1、优化说明 小文件合并优化，分为两个方面，分别是 Map 端输入的小文件合并，和Reduce 端输出的小文件合并。 8.1.1、Map端输入文件合并 合并 Map 端输入的小文件，是指将多个小文件划分到一个切片中，进而由一个 Map Task 去处理。目的是防止为单个小文件启动一个Map Task，浪费计算资源。 相关参数为： --可将多个小文件切片，合并为一个切片，进而由一个map任务处理 set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 8.1.2、Reduce输出文件合并 合并 Reduce 端输出的小文件，是指将多个小文件合并成大文件。目的是减少 HDFS 小文件数量。其原理是根据计算任务输出文件的平均大小进行判断，若符合条件，则单独启动一个额外的任务进行合并。 相关参数为： --开启合并map only任务输出的小文件 set hive.merge.mapfiles=true; --开启合并map reduce任务输出的小文件 set hive.merge.mapredfiles=true; --合并后的文件大小 set hive.merge.size.per.task=256000000; --触发小文件合并任务的阈值，若某计算任务输出的文件平均大小低于该值，则触发合并 set hive.merge.smallfiles.avgsize=16000000; 8.2、优化案例 1）示例用表 现有一个需求，计算各省份订单金额总和，下表为结果表。 hive (default)> drop table if exists order_amount_by_province; create table order_amount_by_province( province_id string comment '省份id', order_amount decimal(16,2) comment '订单金额' ) location '/order_amount_by_province'; 2）示例SQL语句 hive (default)> insert overwrite table order_amount_by_province select province_id, sum(total_amount) from order_detail group by province_id; 3）优化前 根据任务并行度一节所需内容，可分析出，默认情况下，该sql语句的Reduce端并行度为5，故最终输出文件个数也为5，下图为输出文件，可以看出，5个均为小文件。 4）优化思路 若想避免小文件的产生，可采取方案有两个。 （1）合理设置任务的Reduce端并行度 若将上述计算任务的并行度设置为1，就能保证其输出结果只有一个文件。 （2）启用Hive合并小文件优化 设置以下参数： --开启合并map reduce任务输出的小文件 set hive.merge.mapredfiles=true; --合并后的文件大小 set hive.merge.size.per.task=256000000; --触发小文件合并任务的阈值，若某计算任务输出的文件平均大小低于该值，则触发合并 set hive.merge.smallfiles.avgsize=16000000; 再次执行上述的insert语句，观察结果表中的文件，只剩一个了。 九、其他优化 9.1、CBO优化 9.1.1、优化说明 CBO是指Cost based Optimizer，即基于计算成本的优化。 在Hive中，计算成本模型考虑到了：数据的行数、CPU、本地IO、HDFS IO、网络IO等方面。Hive会计算同一SQL语句的不同执行计划的计算成本，并选出成本最低的执行计划。目前CBO在hive的MR引擎下主要用于join的优化，例如多表join的join顺序。 相关参数为： --是否启用cbo优化 set hive.cbo.enable=true; 9.2.2、优化案例 1）示例SQL语句 hive (default)> select * from order_detail od join product_info product on od.product_id=product.id join province_info province on od.province_id=province.id; 2）关闭CBO优化 --关闭cbo优化 set hive.cbo.enable=false; --为了测试效果更加直观，关闭map join自动转换 set hive.auto.convert.join=false; 根据执行计划，可以看出，三张表的join顺序如下： 3）开启CBO优化 --开启cbo优化 set hive.cbo.enable=true; --为了测试效果更加直观，关闭map join自动转换 set hive.auto.convert.join=false; 根据执行计划，可以看出，三张表的join顺序如下： 4）总结 根据上述案例可以看出，CBO优化对于执行计划中join顺序是有影响的，其之所以会将province_info的join顺序提前，是因为province info的数据量较小，将其提前，会有更大的概率使得中间结果的数据量变小，从而使整个计算任务的数据量减小，也就是使计算成本变小。 9.2、谓词下推 9.2.1、优化说明 谓词下推（predicate pushdown）是指，尽量将过滤操作前移，以减少后续计算步骤的数据量。 相关参数为： --是否启动谓词下推（predicate pushdown）优化 set hive.optimize.ppd = true; 需要注意的是： CBO优化也会完成一部分的谓词下推优化工作，因为在执行计划中，谓词越靠前，整个计划的计算成本就会越低。 9.2.2、优化案例 1）示例SQL语句 hive (default)> select * from order_detail join province_info where order_detail.province_id='2'; 2）关闭谓词下推优化 --是否启动谓词下推（predicate pushdown）优化 set hive.optimize.ppd = false; --为了测试效果更加直观，关闭cbo优化 set hive.cbo.enable=false; 通过执行计划可以看到，过滤操作位于执行计划中的join操作之后。 3）开启谓词下推优化 --是否启动谓词下推（predicate pushdown）优化 set hive.optimize.ppd = true; --为了测试效果更加直观，关闭cbo优化 set hive.cbo.enable=false; 通过执行计划可以看出，过滤操作位于执行计划中的join操作之前。 9.3、矢量化查询 Hive的矢量化查询优化，依赖于CPU的矢量化计算，CPU的矢量化计算的基本原理如 Hive的矢量化查询，可以极大的提高一些典型查询场景（例如scans, filters, aggregates, and joins）下的CPU使用效率。 相关参数如下： set hive.vectorized.execution.enabled=true; 若执行计划中，出现“Execution mode: vectorized”字样，即表明使用了矢量化计算。 官网参考连接： https://cwiki.apache.org/confluence/display/Hive/Vectorized+Query+Execution#VectorizedQueryExecution-Limitations 9.4、Fetch抓取 Fetch抓取是指，Hive中对某些情况的查询可以不必使用MapReduce计算。例如：select * from emp;在这种情况下，Hive可以简单地读取emp对应的存储目录下的文件，然后输出查询结果到控制台。 相关参数如下： --是否在特定场景转换为fetch 任务 --设置为none表示不转换 --设置为minimal表示支持select *，分区字段过滤，Limit等 --设置为more表示支持select 任意字段,包括函数，过滤，和limit等 set hive.fetch.task.conversion=more; 9.5、本地模式 9.5.1、优化说明 大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过，有时Hive的输入数据量是非常小的。在这种情况下，为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况，Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集，执行时间可以明显被缩短。 相关参数如下： --开启自动转换为本地模式 set hive.exec.mode.local.auto=true; --设置local MapReduce的最大输入数据量，当输入数据量小于这个值时采用local MapReduce的方式，默认为134217728，即128M set hive.exec.mode.local.auto.inputbytes.max=50000000; --设置local MapReduce的最大输入文件个数，当输入文件个数小于这个值时采用local MapReduce的方式，默认为4 set hive.exec.mode.local.auto.input.files.max=10; 9.5.2、优化案例 1）示例SQL语句 hive (default)> select count(*) from product_info group by category_id; 2）关闭本地模式 set hive.exec.mode.local.auto=false; 3）开启本地模式 set hive.exec.mode.local.auto=true; 9.6、并行执行 Hive会将一个SQL语句转化成一个或者多个Stage，每个Stage对应一个MR Job。默认情况下，Hive同时只会执行一个Stage。但是某SQL语句可能会包含多个Stage，但这多个Stage可能并非完全互相依赖，也就是说有些Stage是可以并行执行的。此处提到的并行执行就是指这些Stage的并行执行。相关参数如下： --启用并行执行优化 set hive.exec.parallel=true; --同一个sql允许最大并行度，默认为8 set hive.exec.parallel.thread.number=8; 9.7、严格模式 Hive可以通过设置某些参数防止危险操作： 1）分区表不使用分区过滤 将hive.strict.checks.no.partition.filter设置为true时，对于分区表，除非where语句中含有分区字段过滤条件来限制范围，否则不允许执行。换句话说，就是用户不允许扫描所有分区。进行这个限制的原因是，通常分区表都拥有非常大的数据集，而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。 2）使用order by没有limit过滤 将hive.strict.checks.orderby.no.limit设置为true时，对于使用了order by语句的查询，要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个Reduce中进行处理，强制要求用户增加这个limit语句可以防止Reduce额外执行很长一段时间（开启了limit可以在数据进入到Reduce之前就减少一部分数据）。 3）笛卡尔积 将hive.strict.checks.cartesian.product设置为true时，会限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN查询的时候不使用ON语句而是使用where语句，这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是，Hive并不会执行这种优化，因此，如果表足够大，那么这个查询就会出现不可控的情况。
一、 Hadoop压缩概述 压缩格式 算法 文件扩展名 是否可切分 DEFLATE DEFLATE .deflate 否 Gzip DEFLATE .gz 否 bzip2 bzip2 .bz2 是 LZO LZO .lzo 是 Snappy Snappy .snappy 否 为了支持多种压缩/解压缩算法，Hadoop 引入了编码/解码器，如下表所示： Hadoop 查看支持压缩的方式hadoop checknative。 Hadoop 在 driver 端设置压缩。 压缩格式 对应的编码/解码器 DEFLATE org.apache.hadoop.io.compress.DefaultCodec gzip org.apache.hadoop.io.compress.GzipCodec bzip2 org.apache.hadoop.io.compress.BZip2Codec LZO com.hadoop.compression.lzo.LzopCodec Snappy org.apache.hadoop.io.compress.SnappyCodec 压缩性能的比较： 压缩算法 原始文件大小 压缩文件大小 压缩速度 解压速度 gzip 8.3GB 1.8GB 17.5MB/s 58MB/s bzip2 8.3GB 1.1GB 2.4MB/s 9.5MB/s LZO 8.3GB 2.9GB 49.3MB/s 74.6MB/s 二、Hive文件格式 为 Hive 表中的数据选择一个合适的文件格式，对提高查询性能的提高是十分有益的。Hive 表数据的存储格式，可以选择 text file、orc、parquet、sequence file等。 2.1、Text File 文本文件是 Hive 默认使用的文件格式，文本文件中的一行内容，就对应 Hive 表中的一行记录。 可通过以下建表语句指定文件格式为文本文件: create table textfile_table (column_specs) stored as textfile; 2.2、ORC 1）文件格式 ORC（Optimized Row Columnar） file format 是 Hive 0.11 版里引入的一种列式存储的文件格式。ORC 文件能够提高 Hive 读写数据和处理数据的性能。 与列式存储相对的是行式存储，下图是两者的对比： 如图所示左边为逻辑表，右边第一个为行式存储，第二个为列式存储。 （1）行存储的特点 查询满足条件的一整行数据的时候，列存储则需要去每个聚集的字段找到对应的每个列的值，行存储只需要找到其中一个值，其余的值都在相邻地方，所以此时行存储查询的速度更快。 （2）列存储的特点 因为每个字段的数据聚集存储，在查询只需要少数几个字段的时候，能大大减少读取的数据量；每个字段的数据类型一定是相同的，列式存储可以针对性的设计更好的设计压缩算法。 前文提到的text file和sequence file都是基于行存储的，orc和parquet是基于列式存储的。 ORC 文件的具体结构如下图所示： 每个 ORC 文件由 Header、Body 和 Tail 三部分组成。 Header 内容为 ORC，用于表示文件类型。 Body 由1个或多个 stripe 组成，每个 stripe 一般为 HDFS 的块大小，每一个 stripe 包含多条记录，这些记录按照列进行独立存储，每个 stripe 里有三部分组成，分别是 Index Data，Row Data，Stripe Footer。 Index Data：一个轻量级的 index，默认是为各列每隔 1W 行做一个索引。每个索引会记录第 n 万行的位置，和最近一万行的最大值和最小值等信息。 Row Data：存的是具体的数据，按列进行存储，并对每个列进行编码，分成多个 Stream 来存储。 Stripe Footer：存放的是各个 Stream 的位置以及各 column 的编码信息。 Tail 由 File Footer 和 PostScript 组成。File Footer 中保存了各 Stripe 的其实位置、索引长度、数据长度等信息，各 Column 的统计信息等；PostScript 记录了整个文件的压缩类型以及 File Footer 的长度信息等。 在读取 ORC 文件时，会先从最后一个字节读取 PostScript 长度，进而读取到 PostScript，从里面解析到 File Footer 长度，进而读取 FileFooter，从中解析到各个 Stripe 信息，再读各个 Stripe，即从后往前读。 2）建表语句 create table orc_table (column_specs) stored as orc tblproperties (property_name=property_value, ...); ORC文件格式支持的参数如下： 参数 默认值 说明 orc.compress ZLIB 压缩格式，可选项：NONE、ZLIB,、SNAPPY orc.compress.size 262,144 每个压缩块的大小（ORC文件是分块压缩的） orc.stripe.size 67,108,864 每个stripe的大小 orc.row.index.stride 10,000 索引步长（每隔多少行数据建一条索引） 1.3、Parquet Parquet 文件是 Hadoop 生态中的一个通用的文件格式，它也是一个列式存储的文件格式。 Parquet 文件的格式如下图所示： 上图展示了一个 Parquet 文件的基本结构，文件的首尾都是该文件的 Magic Code，用于校验它是否是一个 Parquet 文件。 首尾中间由若干个 Row Group 和一个 Footer（File Meta Data）组成。 每个 Row Group 包含多个 Column Chunk，每个 Column Chunk 包含多个 Page。以下是 Row Group、Column Chunk 和 Page三个概念的说明： 行组（Row Group）：一个行组对应逻辑表中的若干行。 列块（Column Chunk）：一个行组中的一列保存在一个列块中。 页（Page）：一个列块的数据会划分为若干个页。 Footer（File Meta Data）中存储了每个行组（Row Group）中的每个列快（Column Chunk）的元数据信息，元数据信息包含了该列的数据类型、该列的编码方式、该类的 Data Page 位置等信息。 建表语句： Create table parquet_table (column_specs) stored as parquet tblproperties (property_name=property_value, ...); 支持的参数如下： 参数 默认值 说明 parquet.compression uncompressed 压缩格式，可选项：uncompressed，snappy，gzip，lzo，brotli，lz4 parquet.block.size 134217728 行组大小，通常与HDFS块大小保持一致 parquet.page.size 1048576 页大小 三、压缩 在 Hive 表中和计算过程中，保持数据的压缩，对磁盘空间的有效利用和提高查询性能都是十分有益的。 3.1、Hive表数据进行压缩 在Hive中，不同文件类型的表，声明数据压缩的方式是不同的。 1）TextFile 若一张表的文件类型为 TextFile，若需要对该表中的数据进行压缩，多数情况下，无需在建表语句做出声明。直接将压缩后的文件导入到该表即可，Hive 在查询表中数据时，可自动识别其压缩格式，进行解压。 需要注意的是，在执行往表中导入数据的 SQL 语句时，用户需设置以下参数，来保证写入表中的数据是被压缩的。 --SQL语句的最终输出结果是否压缩 set hive.exec.compress.output=true; --输出结果的压缩格式（以下示例为snappy） set mapreduce.output.fileoutputformat.compress.codec =org.apache.hadoop.io.compress.SnappyCodec; 2）ORC 若一张表的文件类型为 ORC，若需要对该表数据进行压缩，需在建表语句中声明压缩格式如下： create table orc_table (column_specs) stored as orc tblproperties ("orc.compress"="snappy"); 3）Parquet 若一张表的文件类型为 Parquet，若需要对该表数据进行压缩，需在建表语句中声明压缩格式如下： create table orc_table (column_specs) stored as parquet tblproperties ("parquet.compression"="snappy"); 3.2、计算过程中使用压缩 1）单个 MR 的中间结果进行压缩 单个 MR 的中间结果是指Mapper输出的数据，对其进行压缩可降低 shuffle 阶段的网络 IO，可通过以下参数进行配置： --开启MapReduce中间数据压缩功能 set mapreduce.map.output.compress=true; --设置MapReduce中间数据数据的压缩方式（以下示例为snappy） set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec; 2）单条 SQL 语句的中间结果进行压缩 单条 SQL 语句的中间结果是指，两个 MR（一条SQL语句可能需要通过 MR 进行计算）之间的临时数据，可通过以下参数进行配置： --是否对两个MR之间的临时数据进行压缩 set hive.exec.compress.intermediate=true; --压缩格式（以下示例为snappy） set hive.intermediate.compression.codec= org.apache.hadoop.io.compress.SnappyCodec;
一、分区表和分桶表 Hive 中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录，每个目录就称为该表的一个分区。在查询时通过 where 子句中的表达式选择查询所需要的分区，这样的查询效率会提高很多。 1.1、分区表基本语法 1、创建分区表 hive (default)> create table dept_partition ( deptno int, --部门编号 dname string, --部门名称 loc string --部门位置 ) partitioned by (day string) row format delimited fields terminated by '\t'; 2、分区表读写数据 1）写数据 （1）load 1、数据准备 在/opt/module/hive/datas/路径上创建文件dept_20220401.log，并输入如下内容。 [atguigu@hadoop102 datas]$ vim dept_20220401.log 10 行政部 1700 20 财务部 1800 2、装载语句 hive (default)> load data local inpath '/opt/module/hive/datas/dept_20220401.log' into table dept_partition partition(day='20220401'); （2）insert 将day='20220401'分区的数据插入到day='20220402'分区，可执行如下装载语句 hive (default)> insert overwrite table dept_partition partition (day = '20220402') select deptno, dname, loc from dept_partition where day = '20220401'; 2）读数据 查询分区表数据时，可以将分区字段看作表的伪列，可像使用其他字段一样使用分区字段。 select deptno, dname, loc ,day from dept_partition where day = '20220401'; 3、分区表基本操作 1）查看所有分区信息 hive> show partitions dept_partition; 2）增加分区 （1）创建单个分区 hive (default)> alter table dept_partition add partition(day='20220403'); （2）同时创建多个分区（分区之间不能有逗号） hive (default)> alter table dept_partition add partition(day='20220404') partition(day='20220405'); 3）删除分区 （1）删除单个分区 hive (default)> alter table dept_partition drop partition (day='20220403'); （2）同时删除多个分区（分区之间必须有逗号） hive (default)> alter table dept_partition drop partition (day='20220404'), partition(day='20220405'); 4）修复分区 Hive 将分区表的所有分区信息都保存在了元数据中，只有元数据与 HDFS 上的分区路径一致时，分区表才能正常读写数据。若用户手动创建/删除分区路径，Hive都是感知不到的，这样就会导致 Hive 的元数据和 HDFS 的分区路径不一致。再比如，若分区表为外部表，用户执行drop partition命令后，分区元数据会被删除，而 HDFS 的分区路径不会被删除，同样会导致 Hive 的元数据和 HDFS 的分区路径不一致。 若出现元数据和 HDFS 路径不一致的情况，可通过如下几种手段进行修复。 （1）add partition 若手动创建 HDFS 的分区路径，Hive 无法识别，可通过add partition命令增加分区元数据信息，从而使元数据和分区路径保持一致。 （2）drop partition 若手动删除HDFS的分区路径，Hive无法识别，可通过drop partition命令删除分区元数据信息，从而使元数据和分区路径保持一致。 （3）msck 若分区元数据和 HDFS 的分区路径不一致，还可使用msck命令进行修复，以下是该命令的用法说明。 hive (default)> msck repair table table_name [add/drop/sync partitions]; 说明： msck repair table table_name add partitions：该命令会增加HDFS路径存在但元数据缺失的分区信息。 msck repair table table_name drop partitions：该命令会删除HDFS路径已经删除但元数据仍然存在的分区信息。 msck repair table table_name sync partitions：该命令会同步HDFS路径和元数据分区信息，相当于同时执行上述的两个命令。 msck repair table table_name：等价于msck repair table table_name add partitions命令。 1.2、二级分区表 如果一天内的日志数据量也很大，如何再将数据拆分？答案是二级分区表，例如可以在按天分区的基础上，再对每天的数据按小时进行分区。 1）二级分区表建表语句 hive (default)> create table dept_partition2( deptno int, -- 部门编号 dname string, -- 部门名称 loc string -- 部门位置 ) partitioned by (day string, hour string) row format delimited fields terminated by '\t'; 2）数据装载语句 hive (default)> load data local inpath '/opt/module/hive/datas/dept_20220401.log' into table dept_partition2 partition(day='20220401', hour='12'); 3）查询分区数据 hive (default)> select * from dept_partition2 where day='20220401' and hour='12'; 1.3、动态分区 动态分区是指向分区表 insert 数据时，被写往的分区不由用户指定，而是由每行数据的最后一个字段的值来动态的决定。使用动态分区，可只用一个 insert 语句将数据写入多个分区。 1）动态分区相关参数 （1）动态分区功能总开关（默认true，开启） set hive.exec.dynamic.partition=true （2）严格模式和非严格模式 动态分区的模式，默认 strict（严格模式），要求必须指定至少一个分区为静态分区，nonstrict（非严格模式）允许所有的分区字段都使用动态分区。 set hive.exec.dynamic.partition.mode=nonstrict （3）一条 insert 语句可同时创建的最大的分区个数，默认为1000。 set hive.exec.max.dynamic.partitions=1000 （4）单个 Mapper 或者 Reducer 可同时创建的最大的分区个数，默认为100。 set hive.exec.max.dynamic.partitions.pernode=100 （5）一条 insert 语句可以创建的最大的文件个数，默认100000。 set hive.exec.max.created.files=100000 （6）当查询结果为空时且进行动态分区时，是否抛出异常，默认false。 set hive.error.on.empty.partition=false 2）示例 需求：将dept表中的数据按照地区（loc字段），插入到目标表dept_partition_dynamic的相应分区中。 （1）创建目标分区表 hive (default)> create table dept_partition_dynamic( id int, name string ) partitioned by (loc int) row format delimited fields terminated by '\t'; （2）设置动态分区 set hive.exec.dynamic.partition.mode = nonstrict; hive (default)> insert into table dept_partition_dynamic partition(loc) select deptno, dname, loc from dept; （3）查看目标分区表的分区情况 hive (default)> show partitions dept_partition_dynamic; 二、分桶表 分区提供一个隔离数据和优化查询的便利方式。不过，并非所有的数据集都可形成合理的分区。对于一张表或者分区，Hive 可以进一步组织成桶，也就是更为细粒度的数据范围划分，分区针对的是数据的存储路径，分桶针对的是数据文件。 分桶表的基本原理是，首先为每行数据计算一个指定字段的数据的hash值，然后模以一个指定的分桶数，最后将取模运算结果相同的行，写入同一个文件中，这个文件就称为一个分桶 bucket 。 2.1、分桶表基本语法 1）建表语句 hive (default)> create table stu_buck( id int, name string ) clustered by(id) into 4 buckets row format delimited fields terminated by '\t'; 2）数据装载 （1）数据准备 在/opt/module/hive/datas/路径上创建student.txt文件，并输入如下内容。 1001 student1 1002 student2 1003 student3 ... （2）导入数据到分桶表中 说明：Hive 新版本 load 数据可以直接跑 MapReduce，老版的 Hive 需要将数据传到一张表里，再通过查询的方式导入到分桶表里面。 hive (default)> load data local inpath '/opt/module/datas/student.txt' into table stu_buck; （3）查看创建的分桶表中是否分成4个桶 （4）观察每个分桶中的数据 2.2、分桶排序表 1）建表语句 hive (default)> create table stu_buck_sort( id int, name string ) clustered by(id) sorted by(id) into 4 buckets row format delimited fields terminated by '\t'; 2）数据装载 （1）导入数据到分桶表中 hive (default)> load data local inpath '/opt/module/datas/student.txt' into table stu_buck_sort; （2）查看创建的分桶表中是否分成4个桶 （3）观察每个分桶中的数据
Hive DML(Data Manipulation Language)数据操作
一、Load Load 语句可将文件导入到 Hive 表中。 1）语法 hive> LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]; 关键字说明： （1）local：表示从本地加载数据到 Hive 表；否则从 HDFS 加载数据到 Hive 表。 （2）overwrite：表示覆盖表中已有数据，否则表示追加。 （3）partition：表示上传到指定分区，若目标是分区表，需指定分区。 2）实操示例 （0）创建一张表 hive (default)> create table student( id int, name string ) row format delimited fields terminated by '\t'; （1）加载本地文件到 hive hive (default)> load data local inpath '/opt/module/datas/student.txt' into table student; （2）加载 HDFS 文件到 hive 中 1、上传文件到 HDFS [atguigu@hadoop102 ~]$ hadoop fs -put /opt/module/datas/student.txt /user/atguigu 2、加载 HDFS 上数据，导入完成后去 HDFS 上查看文件是否还存在 hive (default)> load data inpath '/user/atguigu/student.txt' into table student; （3）加载数据覆盖表中已有的数据 1、上传文件到 HDFS hive (default)> hdfs -put /opt/module/datas/student.txt /user/atguigu; 2、加载数据覆盖表中已有的数据 hive (default)> load data inpath '/user/atguigu/student.txt' overwrite into table student; 二、Insert 2.1、将查询结果插入表中 1）语法 INSERT (INTO | OVERWRITE) TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement; 关键字说明： （1）INTO：将结果追加到目标表 （2）OVERWRITE：用结果覆盖原有数据 2）示例 （1）新建一张表 hive (default)> create table student1( id int, name string ) row format delimited fields terminated by '\t'; （2）根据查询结果插入数据 hive (default)> insert overwrite table student1 select id, name from student; 2.2、将给定Values插入表中 1）语法 INSERT (INTO | OVERWRITE) TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...] 2）示例 hive (default)> insert into table student1 values(1,'wangwu'),(2,'zhaoliu'); 2.3、将查询结果写入目标路径 1）语法 INSERT OVERWRITE [LOCAL] DIRECTORY directory [ROW FORMAT row_format] [STORED AS file_format] select_statement; 2）示例 insert overwrite local directory '/opt/module/datas/student' ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe' select id,name from student; 三、Export&Import Export 导出语句可将表的数据和元数据信息一并到处的 HDFS 路径，Import 可将 Export 导出的内容导入 Hive，表的数据和元数据信息都会恢复。Export 和 Import 可用于两个 Hive 实例之间的数据迁移。 1）语法 --导出 EXPORT TABLE tablename TO 'export_target_path' --导入 IMPORT [EXTERNAL] TABLE new_or_original_tablename FROM 'source_path' [LOCATION 'import_target_path'] 2）示例 --导出 hive> export table default.student to '/user/hive/warehouse/export/student'; --导入 hive> import table student2 from '/user/hive/warehouse/export/student';
一、数据库（database） 1.1、创建数据库 1）语法 CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_name=property_value, ...)]; 2）示例 （1）创建一个数据库，不指定路径 hive (default)> create database db_hive1; 注：若不指定路径，其默认路径为：${hive.metastore.warehouse.dir}/database_name.db （2）创建一个数据库，指定路径 hive (default)> create database db_hive2 location '/db_hive2'; （2）创建一个数据库，带有dbproperties hive (default)> create database db_hive3 with dbproperties('create_date'='2022-11-18'); 1.2、查询数据库 1）展示所有数据库 （1）语法 SHOW DATABASES [LIKE 'identifier_with_wildcards']; 注：like通配表达式说明：*表示任意个任意字符，|表示或的关系。 （2）示例 hive> show databases like 'db_hive*'; OK db_hive_1 db_hive_2 2）查看数据库信息 （1）语法 DESCRIBE DATABASE [EXTENDED] db_name; （2）示例 1、查看基本信息 hive> desc database db_hive3; OK db_hive hdfs://hadoop102:8020/user/hive/warehouse/db_hive.db atguigu USER 2、查看更多信息 hive> desc database extended db_hive3; OK db_name comment location owner_name owner_type parameters db_hive3 hdfs://hadoop102:8020/user/hive/warehouse/db_hive3.db atguigu USER {create_date=2022-11-18} 1.3、修改数据库 用户可以使用alter database命令修改数据库某些信息，其中能够修改的信息包括dbproperties、location、owner user。需要注意的是：修改数据库 location，不会改变当前已有表的路径信息，而只是改变后续创建的新表的默认的父目录。 1）语法 --修改dbproperties ALTER DATABASE database_name SET DBPROPERTIES (property_name=property_value, ...); --修改location ALTER DATABASE database_name SET LOCATION hdfs_path; --修改owner user ALTER DATABASE database_name SET OWNER USER user_name; 2）示例 （1）修改 dbproperties hive> ALTER DATABASE db_hive3 SET DBPROPERTIES ('create_date'='2022-11-20'); 1.4 删除数据库 1）语法 DROP DATABASE [IF EXISTS] database_name [RESTRICT|CASCADE]; 注：RESTRICT：严格模式，若数据库不为空，则会删除失败，默认为该模式。 CASCADE：级联模式，若数据库不为空，则会将库中的表一并删除。 2）示例 （1）删除空数据库 hive> drop database db_hive2; （2）删除非空数据库 hive> drop database db_hive3 cascade; 1.5、切换当前数据库 1）语法 USE database_name; 二、表（table） 2.1、创建表 2.1.1、语法 1）普通建表 （1）完整语法 CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name [(col_name data_type [COMMENT col_comment], ...)] [COMMENT table_comment] [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path] [TBLPROPERTIES (property_name=property_value, ...)] （2）关键字说明： 1、TEMPORARY 临时表，该表只在当前会话可见，会话结束，表会被删除。 2、EXTERNAL（重点） 外部表，与之相对应的是内部表（管理表）。管理表意味着 Hive 会完全接管该表，包括元数据和 HDFS 中的数据。而外部表则意味着 Hive 只接管元数据，而不完全接管 HDFS 中的数据。 3、data_type（重点） Hive中的字段类型可分为基本数据类型和复杂数据类型。 基本数据类型如下： tinyint 1byte有符号整数 smallint 2byte有符号整数 int 4byte有符号整数 bigint 8byte有符号整数 boolean 布尔类型，true或者false float 单精度浮点数 double 双精度浮点数 decimal 十进制精准数字类型 / decimal(16,2) varchar 字符序列，需指定最大长度，最大长度的范围是[1,65535] / varchar(32) string 字符串，无需指定最大长度 timestamp 时间类型 binary 二进制数据 复杂数据类型如下： 注：类型转换 Hive的基本数据类型可以做类型转换，转换的方式包括隐式转换以及显示转换。 方式一：隐式转换 具体规则如下： a、任何整数类型都可以隐式地转换为一个范围更广的类型，如 tinyint 可以转换成 int，int 可以转换成 bigint。 b、所有整数类型、float 和 string 类型都可以隐式地转换成 double。 c、tinyint、smallint、int 都可以转换为 float。 d、boolean 类型不可以转换为任何其它的类型。 详情可参考 Hive 官方说明：Allowed Implicit Conversions 方式二：显示转换 可以借助cast函数完成显示的类型转换 a、语法 cast(expr as <type>) b、示例 hive (default)> select '1' + 2, cast('1' as int) + 2; 3.0 3 4、PARTITIONED BY（重点） 创建分区表 5、CLUSTERED BY ... SORTED BY...INTO ... BUCKETS（重点） 创建分桶表 6、ROW FORMAT（重点） 指定 SERDE，SERDE 是Serializer and Deserializer的简写。Hive 使用 SERDE 序列化和反序列化每行数据。详情可参考 Hive-Serde。语法说明如下： 语法一：DELIMITED 关键字表示对文件中的每个字段按照特定分割符进行分割，其会使用默认的 SERDE 对每行数据进行序列化和反序列化。 ROW FORAMT DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char] [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char] [NULL DEFINED AS char] 注： fields terminated by ：列分隔符 collection items terminated by ： map、struct和array中每个元素之间的分隔符 map keys terminated by ：map中的key与value的分隔符 lines terminated by ：行分隔符 语法二：SERDE 关键字可用于指定其他内置的 SERDE 或者用户自定义的 SERDE。例如 JSON SERDE，可用于处理 JSON 字符串。 ROW FORMAT SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value, ...)] 7、STORED AS（重点） 指定文件格式，常用的文件格式有，textfile（默认值），sequence file，orc file、parquet file等等。 8、LOCATION 指定表所对应的 HDFS 路径，若不指定路径，其默认值为 ${hive.metastore.warehouse.dir}/db_name.db/table_name 9、TBLPROPERTIES 用于配置表的一些 KV 键值对参数 2）Create Table As Select（CTAS）建表 该语法允许用户利用 select 查询语句返回的结果，直接建表，表的结构和查询语句的结构保持一致，且保证包含 select 查询语句放回的内容。 CREATE [TEMPORARY] TABLE [IF NOT EXISTS] table_name [COMMENT table_comment] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path] [TBLPROPERTIES (property_name=property_value, ...)] [AS select_statement] 3）Create Table Like语法 该语法允许用户复刻一张已经存在的表结构，与上述的 CTAS 语法不同，该语法创建出来的表中不包含数据。 CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name [LIKE exist_table_name] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path] [TBLPROPERTIES (property_name=property_value, ...)] 2.1.2、示例 1）内部表与外部表 （1）内部表 Hive 中默认创建的表都是的内部表，有时也被称为管理表。对于内部表，Hive 会完全管理表的元数据和数据文件。 创建内部表如下： create table if not exists student( id int, name string ) row format delimited fields terminated by '\t' location '/user/hive/warehouse/student'; 准备其需要的文件如下，注意字段之间的分隔符。 [atguigu@hadoop102 datas]$ vim /opt/module/datas/student.txt 1001 student1 1002 student2 1003 student3 ... 上传文件到Hive表指定的路径 [atguigu@hadoop102 datas]$ hadoop fs -put student.txt /user/hive/warehouse/student 删除表，观察数据 HDFS 中的数据文件是否还在。（被删除了） hive (default)> drop table student; （2）外部表 外部表通常可用于处理其他工具上传的数据文件，对于外部表，Hive 只负责管理元数据，不负责管理 HDFS 中的数据文件。 创建外部表如下： create external table if not exists student( id int, name string ) row format delimited fields terminated by '\t' location '/user/hive/warehouse/student'; 上传文件到 Hive 表指定的路径 [atguigu@hadoop102 datas]$ hadoop fs -put student.txt /user/hive/warehouse/student 删除表，观察数据HDFS中的数据文件是否还在 hive (default)> drop table student; 2）SERDE 和复杂数据类型 SERDE 和复杂数据类型的使用。 若现有如下格式的 JSON 文件需要由 Hive 进行分析处理，请考虑如何设计表？ 注：以下内容为格式化之后的结果，文件中每行数据为一个完整的 JSON 字符串。 { "name": "dasongsong", "friends": [ "bingbing", "lili" ], "students": { "xiaohaihai": 18, "xiaoyangyang": 16 }, "address": { "street": "hui long guan", "city": "beijing", "postal_code": 10010 } } 我们可以考虑使用专门负责 JSON 文件的 JSON Serde，设计表字段时，表的字段与 JSON 字符串中的一级字段保持一致，对于具有嵌套结构的 JSON 字符串，考虑使用合适复杂数据类型保存其内容。最终设计出的表结构如下： hive> create table teacher ( name string, friends array<string>, students map<string,int>, address struct<city:string,street:string,postal_code:int> ) row format serde 'org.apache.hadoop.hive.serde2.JsonSerDe' location '/user/hive/warehouse/teacher'; 创建该表，并准备以下文件。注意，需要确保文件中每行数据都是一个完整的 JSON 字符串，JSON SERDE 才能正确的处理。 [atguigu@hadoop102 datas]$ vim /opt/module/datas/teacher.txt {"name":"dasongsong","friends":["bingbing","lili"],"students":{"xiaohaihai":18,"xiaoyangyang":16},"address":{"street":"hui long guan","city":"beijing","postal_code":10010}} 上传文件到 Hive 表指定的路径 [atguigu@hadoop102 datas]$ hadoop fs -put teacher.txt /user/hive/warehouse/teacher 尝试从复杂数据类型的字段中取值 3）create table as select和create table like （1）create table as select hive> create table teacher1 as select * from teacher; （2）create table like hive> create table teacher2 like teacher; 2.2、查看表 1）展示所有表 （1）语法 SHOW TABLES [IN database_name] LIKE ['identifier_with_wildcards']; 注：like 通配表达式说明：*表示任意个任意字符，|表示或的关系。 （2）示例 hive> show tables like 'stu*'; 2）查看表信息 （1）语法 DESCRIBE [EXTENDED | FORMATTED] [db_name.]table_name 注：EXTENDED：展示详细信息 FORMATTED：对详细信息进行格式化的展示 （2）示例 1、查看基本信息 hive> desc stu; 2、查看更多信息 hive> desc formatted stu; 2.3、修改表 1）重命名表 （1）语法 ALTER TABLE table_name RENAME TO new_table_name （2）示例 hive (default)> alter table stu rename to stu1; 2）修改列信息 （1）语法 1、增加列 该语句允许用户增加新的列，新增列的位置位于末尾。 ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], ...) 2、更新列 该语句允许用户修改指定列的列名、数据类型、注释信息以及在表中的位置。 ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name] 3、替换列 该语句允许用户用新的列集替换表中原有的全部列。 ALTER TABLE table_name REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...) 3）示例 （1）查询表结构 hive (default)> desc stu; （2）添加列 hive (default)> alter table stu add columns(age int); （3）查询表结构 hive (default)> desc stu; （4）更新列 hive (default)> alter table stu change column age ages double; （6）替换列 hive (default)> alter table stu replace columns(id int, name string); 2.4、删除表 1）语法 DROP TABLE [IF EXISTS] table_name; 2）示例 hive (default)> drop table stu; 2.5、清空表 1）语法 TRUNCATE [TABLE] table_name 注意：truncate 只能清空管理表，不能删除外部表中数据。 2）示例 hive (default)> truncate table student;
一、Hive入门 1.1、关于Hive 1）Hive简介 Hive 是由Facebook 开源，基于 Hadoop 的一个数据仓库工具，可以将结构化的数据文件映射为一张表，并提供类SQL查询功能。 那为什么会有Hive呢？它是为了解决什么问题而诞生的呢？ 下面通过一个案例，来快速了解一下Hive。 例如：需求，统计单词出现个数。 （1）在 Hadoop 中我们用 MapReduce 程序实现的，当时需要写Mapper、Reducer和Driver三个类，并实现对应逻辑，相对繁琐。 （2）如果通过Hive SQL实现，一行就搞定了，简单方便，容易理解。 select count(*) from test group by id; 2）Hive本质 Hive 是一个 Hadoop 客户端，用于将HQL（Hive SQL）转化成MapReduce程序。 （1）Hive 中每张表的数据存储在 HDFS。 （2）Hive 分析数据底层的实现是 MapReduce（也可配置为Spark或者Tez）。 （3）执行程序运行在 Yarn 上。 1.2、Hive架构原理 1.2.1、用户接口：Client CLI（command-line interface）、JDBC/ODBC。 说明：JDBC 和 ODBC 的区别。 （1）JDBC 的移植性比 ODBC 好；（通常情况下，安装完 ODBC 驱动程序之后，还需要经过确定的配置才能够应用。而不相同的配置在不相同数据库服务器之间不能够通用。所以，安装一次就需要再配置一次。JDBC 只需要选取适当的 JDBC 数据库驱动程序，就不需要额外的配置。在安装过程中，JDBC 数据库驱动程序会自己完成有关的配置。） （2）两者使用的语言不同，JDBC 在 Java 编程时使用，ODBC 一般在 C/C++ 编程时使用。 1.2.2、元数据：Metastore 元数据包括：数据库（默认是default）、表名、表的拥有者、列/分区字段、表的类型（是否是外部表）、表的数据所在目录等。 默认存储在自带的derby数据库中，由于 derby 数据库只支持单客户端访问，生产环境中为了多人开发，推荐使用 MySQL 存储 Metastore。 1.2.3、驱动器：Driver （1）解析器（SQLParser）：将SQL字符串转换成抽象语法树（AST） （2）语义分析（Semantic Analyzer）：将AST进一步划分为QeuryBlock （3）逻辑计划生成器（Logical Plan Gen）：将语法树生成逻辑计划 （4）逻辑优化器（Logical Optimizer）：对逻辑计划进行优化 （5）物理计划生成器（Physical Plan Gen）：根据优化后的逻辑计划生成物理计划 （6）物理优化器（Physical Optimizer）：对物理计划进行优化 （7）执行器（Execution）：执行该计划，得到查询结果并返回给客户端 抽象语法树： 逻辑计划与物理计划： 1.2.4、Hadoop 使用 HDFS 进行存储，可以选择 MapReduce/Tez/Spark 进行计算。 二、Hive安装 2.1、Hive安装地址 1）Hive官网地址 http://hive.apache.org/ 2）文档查看地址 https://cwiki.apache.org/confluence/display/Hive/GettingStarted 3）下载地址 http://archive.apache.org/dist/hive/ 4）github地址 https://github.com/apache/hive 2.2、Hive安装部署 2.2.1、安装Hive 1）把apache-hive-3.1.3-bin.tar.gz上传到Linux的/opt/software目录下 2）解压apache-hive-3.1.3-bin.tar.gz到/opt/module/目录下面 tar -zxvf /opt/software/apache-hive-3.1.3-bin.tar.gz -C /opt/module/ 3）修改apache-hive-3.1.3-bin.tar.gz的名称为hive [atguigu@hadoop102 software]$ mv /opt/module/apache-hive-3.1.3-bin/ /opt/module/hive 4）修改/etc/profile.d/my_env.sh，添加环境变量 sudo vim /etc/profile.d/my_env.sh （1）添加内容 #HIVE_HOME export HIVE_HOME=/opt/module/hive export PATH=$PATH:$HIVE_HOME/bin （2）source一下 source /etc/profile.d/my_env.sh 5）初始化元数据库（默认是derby数据库） [atguigu@hadoop102 hive]$ bin/schematool -dbType derby -initSchema 2.2.2、启动并使用Hive 1）启动Hive bin/hive 2）使用Hive hive> show databases; hive> show tables; hive> create table stu(id int, name string); hive> insert into stu values(1,"ss"); hive> select * from stu; 观察 HDFS 的路径/user/hive/warehouse/stu，体会 Hive 与 Hadoop 之间的关系。 Hive 中的表在 Hadoop 中是目录；Hive 中的数据在 Hadoop 中是文件。 3）在 Xshell 窗口中开启另一个窗口开启 Hive，在/tmp/atguigu目录下监控hive.log文件 [atguigu@hadoop102 atguigu]$ tail -f hive.log Caused by: ERROR XSDB6: Another instance of Derby may have already booted the database /opt/module/hive/metastore_db. at org.apache.derby.iapi.error.StandardException.newException(Unknown Source) at org.apache.derby.iapi.error.StandardException.newException(Unknown Source) at org.apache.derby.impl.store.raw.data.BaseDataFileFactory.privGetJBMSLockOnDB(Unknown Source) at org.apache.derby.impl.store.raw.data.BaseDataFileFactory.run(Unknown Source) ... 原因在于Hive默认使用的元数据库为 derby。derby 数据库的特点是同一时间只允许一个客户端访问。如果多个 Hive 客户端同时访问，就会报错。由于在企业开发中，都是多人协作开发，需要多客户端同时访问Hive，怎么解决呢？我们可以将 Hive 的元数据改为用 MySQL 存储，MySQL 支持多客户端同时访问。 4）首先退出 hive 客户端。然后在 Hive 的安装目录下将derby.log和metastore_db删除，顺便将 HDFS 上目录删除 hive> quit; [atguigu@hadoop102 hive]$ rm -rf derby.log metastore_db [atguigu@hadoop102 hive]$ hadoop fs -rm -r /user 5）删除 HDFS 中/user/hive/warehouse/stu中数据 2.3、MySQL安装 略 2.4、配置Hive元数据存储到MySQL 2.4.1、配置元数据到MySQL 1）新建 Hive 元数据库 #登录MySQL [atguigu@hadoop102 software]$ mysql -uroot -p123456 #创建Hive元数据库 mysql> create database metastore; mysql> quit; 2）将 MySQL 的 JDBC 驱动拷贝到 Hive 的 lib 目录下。 [atguigu@hadoop102 software]$ cp /opt/software/mysql-connector-java-5.1.37.jar $HIVE_HOME/lib 3）在$HIVE_HOME/conf目录下新建hive-site.xml文件 [atguigu@hadoop102 software]$ vim $HIVE_HOME/conf/hive-site.xml 添加如下内容： <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://hadoop102:3306/metastore?useSSL=false</value> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>123456</value> </property> <property> <name>hive.metastore.warehouse.dir</name> <value>/user/hive/warehouse</value> </property> </configuration> 5）初始化 Hive 元数据库（修改为采用 MySQL 存储元数据） [atguigu@hadoop102 hive]$ bin/schematool -dbType mysql -initSchema -verbose 2.4.2、验证元数据是否配置成功 1）再次启动 Hive [atguigu@hadoop102 hive]$ bin/hive 2）使用 Hive hive> show databases; hive> show tables; hive> create table stu(id int, name string); hive> insert into stu values(1,"ss"); hive> select * from stu; 3）在 Xshell 窗口中开启另一个窗口开启 Hive（两个窗口都可以操作Hive，没有出现异常） hive> show databases; hive> show tables; hive> select * from stu; 2.4.3、查看MySQL中的元数据 1）登录MySQL [atguigu@hadoop102 hive]$ mysql -uroot -p123456 2）查看元数据库metastore mysql> show databases; mysql> use metastore; mysql> show tables; （1）查看元数据库中存储的库信息 mysql> select * from DBS; +-------+-----------------------+-------------------------------------------+---------+------------+------------+-----------+ | DB_ID | DESC | DB_LOCATION_URI | NAME | OWNER_NAME | OWNER_TYPE | CTLG_NAME | +-------+-----------------------+-------------------------------------------+---------+------------+------------+-----------+ | 1 | Default Hive database | hdfs://hadoop102:8020/user/hive/warehouse | default | public | ROLE | hive | +-------+-----------------------+-------------------------------------------+---------+------------+------------+-----------+ （2）查看元数据库中存储的表信息 mysql> select * from TBLS; +--------+-------------+-------+------------------+---------+------------+-----------+-------+----------+---------------+ | TBL_ID | CREATE_TIME | DB_ID | LAST_ACCESS_TIME | OWNER | OWNER_TYPE | RETENTION | SD_ID | TBL_NAME | TBL_TYPE | +--------+-------------+-------+------------------+---------+------------+-----------+-------+----------+---------------+ | 1 | 1656318303 | 1 | 0 | atguigu | USER | 0 | 1 | stu | MANAGED_TABLE | +--------+-------------+-------+------------------+---------+------------+-----------+-------+----------+---------------+ （3）查看元数据库中存储的表中列相关信息 mysql> select * from COLUMNS_V2; +-------+----------+---------+------------+-------------+-------------+--------+ | CS_ID | CAT_NAME | DB_NAME | TABLE_NAME | COLUMN_NAME | COLUMN_TYPE | TBL_ID | +-------+----------+---------+------------+-------------+-------------+--------+ | 1 | hive | default | stu | id | int | 1 | | 2 | hive | default | stu | name | string | 1 | +-------+----------+---------+------------+-------------+-------------+--------+ 2.5、Hive服务部署 2.5.1、hiveserver2服务 Hive 的 hiveserver2 服务的作用是提供 jdbc/odbc 接口，为用户提供远程访问Hive数据的功能，例如用户期望在个人电脑中访问远程服务中的 Hive 数据，就需要用到 Hiveserver2。 1）用户说明 在远程访问 Hive 数据时，客户端并未直接访问 Hadoop 集群，而是由 Hivesever2 代理访问。由于Hadoop集群中的数据具备访问权限控制，所以此时需考虑一个问题：那就是访问 Hadoop 集群的用户身份是谁？是 Hiveserver2 的启动用户？还是客户端的登录用户？ 答案是都有可能，具体是谁，由 Hiveserver2 的hive.server2.enable.doAs参数决定，该参数的含义是是否启用Hiveserver2 用户模拟的功能。若启用，则 Hiveserver2 会模拟成客户端的登录用户去访问 Hadoop 集群的数据，不启用，则Hivesever2 会直接使用启动用户访问 Hadoop 集群数据。模拟用户的功能，默认是开启的。 具体逻辑如下： 未开启用户模拟功能： 生产环境，推荐开启用户模拟功能，因为开启后才能保证各用户之间的权限隔离。 2）hiveserver2部署 （1）Hadoop端配置 hivesever2 的模拟用户功能，依赖于 Hadoop 提供的proxy user（代理用户功能），只有 Hadoop 中的代理用户才能模拟其他用户的身份访问 Hadoop 集群。因此，需要将 hiveserver2 的启动用户设置为 Hadoop 的代理用户，配置方式如下： 修改配置文件core-site.xml，然后记得分发三台机器 [atguigu@hadoop102 ~]$ cd $HADOOP_HOME/etc/hadoop [atguigu@hadoop102 hadoop]$ vim core-site.xml 增加如下配置： <property> <name>hadoop.proxyuser.atguigu.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.atguigu.groups</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.atguigu.users</name> <value>*</value> </property> （2）Hive端配置 在hive-site.xml文件中添加如下配置信息 [atguigu@hadoop102 conf]$ vim hive-site.xml <property> <name>hive.server2.thrift.bind.host</name> <value>hadoop102</value> </property> <property> <name>hive.server2.thrift.port</name> <value>10000</value> </property> 3）测试 （1）启动 hiveserver2 [atguigu@hadoop102 hive]$ bin/hive --service hiveserver2 如果想保持命令启动的进程在后台运行 [atguigu@hadoop202 hive]$ nohup hive --service hiveserver2 2>&1 （2）使用命令行客户端beeline进行远程访问 启动beeline客户端 [atguigu@hadoop102 hive]$ bin/beeline -u jdbc:hive2://hadoop102:10000 -n atguigu 看到如下界面 Connecting to jdbc:hive2://hadoop102:10000 Connected to: Apache Hive (version 3.1.3) Driver: Hive JDBC (version 3.1.3) Transaction isolation: TRANSACTION_REPEATABLE_READ Beeline version 3.1.3 by Apache Hive 0: jdbc:hive2://hadoop102:10000> （3）使用 Datagrip 图形化客户端进行远程访问 4）配置 DataGrip 连接 （1）创建连接 （2）配置连接属性 所有属性配置，和 Hive 的 beeline 客户端配置一致即可。初次使用，配置过程会提示缺少 JDBC 驱动，按照提示下载即可。 2.5.2、metastore服务 Hive 的 metastore 服务的作用是为 Hive CLI 或者 Hiveserver2 提供元数据访问接口。 1）metastore运行模式 metastore 有两种运行模式，分别为嵌入式模式和独立服务模式。下面分别对两种模式进行说明： （1）嵌入式模式 （2）独立服务模式 生产环境中，不推荐使用嵌入式模式。因为其存在以下两个问题： （1）嵌入式模式下，每个 Hive CLI 都需要直接连接元数据库，当 Hive CLI 较多时，数据库压力会比较大。 （2）每个客户端都需要用户元数据库的读写权限，元数据库的安全得不到很好的保证。 2）metastore部署 （1）嵌入式模式 嵌入式模式下，只需保证 Hiveserver2 和每个 Hive CLI 的配置文件hive-site.xml中包含连接元数据库所需要的以下参数即可： <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://hadoop102:3306/metastore?useSSL=false</value> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>123456</value> </property> （2）独立服务模式 独立服务模式需做以下配置： 首先，保证 metastore 服务的配置文件hive-site.xml中包含连接元数据库所需的以下参数： <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://hadoop102:3306/metastore?useSSL=false</value> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>123456</value> </property> 其次，保证 Hiveserver2 和每个 Hive CLI 的配置文件hive-site.xml中包含访问metastore服务所需的以下参数： <property> <name>hive.metastore.uris</name> <value>thrift://hadoop102:9083</value> </property> 注意：主机名需要改为 metastore 服务所在节点，端口号无需修改，metastore 服务的默认端口就是9083。 3）测试 此时启动 Hive CLI，执行show databases 语句，会出现一下错误提示信息： hive (default)> show databases; FAILED: HiveException java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient 这是因为我们在 Hive CLI 的配置文件中配置了hive.metastore.uris参数，此时 Hive CLI 会去请求我们执行的 metastore 服务地址，所以必须启动 metastore 服务才能正常使用。 metastore 服务的启动命令如下： [atguigu@hadoop202 hive]$ hive --service metastore 2022-04-24 16:58:08: Starting Hive Metastore Server 注意：启动后该窗口不能再操作，需打开一个新的 Xshell 窗口来对 Hive 操作。 重新启动 Hive CLI，并执行 show databases 语句，就能正常访问了 [atguigu@hadoop202 hive]$ bin/hive 2.5.3、编写Hive服务启动脚本（了解） 1）前台启动的方式导致需要打开多个Xshell窗口，可以使用如下方式后台方式启动 nohup：放在命令开头，表示不挂起，也就是关闭终端进程也继续保持运行状态 /dev/null：是Linux文件系统中的一个文件，被称为黑洞，所有写入该文件的内容都会被自动丢弃 2>&1：表示将错误重定向到标准输出上 &：放在命令结尾，表示后台运行 一般会组合使用：nohup [xxx命令操作]> file 2>&1 &，表示将xxx命令运行的结果输出到 file 中，并保持命令启动的进程在后台运行。 [atguigu@hadoop202 hive]$ nohup hive --service metastore 2>&1 & [atguigu@hadoop202 hive]$ nohup hive --service hiveserver2 2>&1 2）为了方便使用，可以直接编写脚本来管理服务的启动和关闭 [atguigu@hadoop102 hive]$ vim $HIVE_HOME/bin/hiveservices.sh 内容如下： hiveservices.sh 3）添加执行权限 [atguigu@hadoop102 hive]$ chmod +x $HIVE_HOME/bin/hiveservices.sh 4）启动Hive后台服务 [atguigu@hadoop102 hive]$ hiveservices.sh start 2.6、Hive使用技巧 2.6.1、Hive常用交互命令 [atguigu@hadoop102 hive]$ bin/hive -help usage: hive -d,--define <key=value> Variable subsitution to apply to hive commands. e.g. -d A=B or --define A=B --database <databasename> Specify the database to use -e <quoted-query-string> SQL from command line -f <filename> SQL from files -H,--help Print help information --hiveconf <property=value> Use value for given property --hivevar <key=value> Variable subsitution to apply to hive commands. e.g. --hivevar A=B -i <filename> Initialization SQL file -S,--silent Silent mode in interactive shell -v,--verbose Verbose mode (echo executed SQL to the console) 1）在 Hive 命令行里创建一个表 student，并插入1条数据 hive (default)> create table student(id int,name string); OK Time taken: 1.291 seconds hive (default)> insert into table student values(1,"zhangsan"); hive (default)> select * from student; OK student.id student.name 1 zhangsan Time taken: 0.144 seconds, Fetched: 1 row(s) 2）-e不进入hive的交互窗口执行 hql 语句 [atguigu@hadoop102 hive]$ bin/hive -e "select id from student;" 3）-f执行脚本中的 hql 语句 （1）在/opt/module/hive/下创建 datas 目录并在datas目录下创建hivef.sql文件 [atguigu@hadoop102 hive]$ mkdir datas [atguigu@hadoop102 datas]$ vim hivef.sql （2）文件中写入正确的hql语句 select * from student; （3）执行文件中的hql语句 [atguigu@hadoop102 hive]$ bin/hive -f /opt/module/hive/datas/hivef.sql （4）执行文件中的 hql 语句并将结果写入文件中 [atguigu@hadoop102 hive]$ bin/hive -f /opt/module/hive/datas/hivef.sql > /opt/module/hive/datas/hive_result.txt 2.6.2、Hive参数配置方式 1）查看当前所有的配置信息 hive>set; 2）参数的配置三种方式 （1）配置文件方式 默认配置文件：hive-default.xml 用户自定义配置文件：hive-site.xml 注意：用户自定义配置会覆盖默认配置。另外，Hive 也会读入 Hadoop 的配置，因为 Hive 是作为 Hadoop 的客户端启动的， Hive 的配置会覆盖 Hadoop 的配置。配置文件的设定对本机启动的所有 Hive 进程都有效。 （2）命令行参数方式 1、启动 Hive 时，可以在命令行添加-hiveconf param=value来设定参数。例如： [atguigu@hadoop103 hive]$ bin/hive -hiveconf mapreduce.job.reduces=10; 注意：仅对本次 Hive 启动有效。 2、查看参数设置 hive (default)> set mapreduce.job.reduces; （3）参数声明方式 可以在 HQ L中使用 SET 关键字设定参数，例如： hive(default)> set mapreduce.job.reduces=10; 注意：仅对本次 Hive 启动有效。 查看参数设置： hive(default)> set mapreduce.job.reduces; 上述三种设定方式的优先级依次递增。即配置文件 < 命令行参数 < 参数声明。注意某些系统级的参数，例如 log4j 相关的设定，必须用前两种方式设定，因为那些参数的读取在会话建立以前已经完成了。 2.6.3、Hive常见属性配置 1）Hive客户端显示当前库和表头 （1）在hive-site.xml中加入如下两个配置: <property> <name>hive.cli.print.header</name> <value>true</value> <description>Whether to print the names of the columns in query output.</description> </property> <property> <name>hive.cli.print.current.db</name> <value>true</value> <description>Whether to include the current database in the Hive prompt.</description> </property> （2）hive 客户端在运行时可以显示当前使用的库和表头信息 [atguigu@hadoop102 conf]$ hive hive (default)> select * from stu; OK stu.id stu.name 1 ss Time taken: 1.874 seconds, Fetched: 1 row(s) hive (default)> 2）Hive 运行日志路径配置 （1）Hive 的 log 默认存放在/tmp/atguigu/hive.log目录下（当前用户名下） [atguigu@hadoop102 atguigu]$ pwd /tmp/atguigu [atguigu@hadoop102 atguigu]$ ls hive.log hive.log.2022-06-27 （2）修改Hive的log存放日志到/opt/module/hive/logs 1、修改$HIVE_HOME/conf/hive-log4j2.properties.template文件名称为hive-log4j2.properties [atguigu@hadoop102 conf]$ pwd /opt/module/hive/conf [atguigu@hadoop102 conf]$ mv hive-log4j2.properties.template hive-log4j2.properties 2、在hive-log4j2.properties文件中修改log存放位置 [atguigu@hadoop102 conf]$ vim hive-log4j2.properties 修改配置如下 property.hive.log.dir=/opt/module/hive/logs 3）Hive 的 JVM 堆内存设置 新版本的 Hive 启动的时候，默认申请的 JVM 堆内存大小为 256M，JVM堆内存申请的太小，导致后期开启本地模式，执行复杂的 SQL 时经常会报错：java.lang.OutOfMemoryError: Java heap space，因此最好提前调整一下HADOOP_HEAPSIZE这个参数。 （1）修改$HIVE_HOME/conf下的hive-env.sh.template为hive-env.sh [atguigu@hadoop102 conf]$ pwd /opt/module/hive/conf [atguigu@hadoop102 conf]$ mv hive-env.sh.template hive-env.sh （2）将hive-env.sh其中的参数 export HADOOP_HEAPSIZE修改为 2048，重启 Hive。 修改前 # The heap size of the jvm stared by hive shell script can be controlled via: # export HADOOP_HEAPSIZE=1024 修改后 # The heap size of the jvm stared by hive shell script can be controlled via: export HADOOP_HEAPSIZE=2048 4）关闭 Hadoop 虚拟内存检查 在yarn-site.xml中关闭虚拟内存检查（虚拟内存校验，如果已经关闭了，就不需要配了）。 （1）修改前记得先停Hadoop [atguigu@hadoop102 hadoop]$ pwd /opt/module/hadoop-3.1.3/etc/hadoop [atguigu@hadoop102 hadoop]$ vim yarn-site.xml （2）添加如下配置 <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property> （3）修改完后记得分发yarn-site.xml，并重启 yarn。