Hive SQL(进阶)

Hive SerDe

一、SerDe 的核心作用

Hive 本身不直接解析数据文件(如 TextFile、JSON、Parquet),而是通过 SerDe 完成:

  • 反序列化(Deserialize) :读取 HDFS 数据文件时,SerDe 把字节流 / 文本行拆分成表的字段(比如把 1,小明,lol-book 拆成 id=1、name = 小明、hobby=lol-book);
  • 序列化(Serialize) :写入数据时,SerDe 把 Hive 表的字段数据转换成指定格式的字节流 / 文本行(比如把 id=2、name = 小红 转换成 2,小红,book-movie)。

二、Hive 常用 SerDe 类型(按场景分类)

不同数据格式对应不同的 SerDe,以下是最常用的 4 类,覆盖 90% 的场景:

| SerDe 类型 | 全类名 | 适用数据格式 |
| LazySimpleSerDe | org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe | Hive 默认 SerDe,分隔符文本(逗号 / 制表符 / 自定义分隔符) |
| JSONSerDe | org.apache.hive.hcatalog.data.JsonSerDe(Hive 内置) | JSON 格式(单行 JSON / 多行 JSON) |
| RegexSerDe | org.apache.hadoop.hive.serde2.RegexSerDe | 用正则表达式解析无固定分隔符的文本(如日志、固定格式字符串) |

ParquetSerDe org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe 适配 Parquet 文件,高效压缩,支持复杂类型,大数据场景首选

三、SerDe 的配置方式(创建表时指定)

SerDe 需在 CREATE TABLE 中通过 ROW FORMAT SERDE 指定,配合 SERDEPROPERTIES 配置解析规则(如分隔符、正则、JSON 映射)。

场景 1:默认 SerDe(LazySimpleSerDe)------ 分隔符文本

LazySimpleSerDe 是 Hive 默认 SerDe,无需显式指定,仅需配置分隔符:

sql 复制代码
CREATE TABLE person (
    id INT,
    name STRING,
    hobby STRING
)
ROW FORMAT DELIMITED  -- 简写,底层用 LazySimpleSerDe
FIELDS TERMINATED BY ','  -- 字段分隔符:逗号
COLLECTION ITEMS TERMINATED BY '-'  -- 集合元素分隔符:短横线
LINES TERMINATED BY '\n';  -- 行分隔符:换行
-- 等价于显式指定:
-- ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
-- WITH SERDEPROPERTIES (
--   'field.delim' = ',',
--   'collection.delim' = '-'
-- );

场景 2:RegexSerDe ------ 正则解析日志

适配无固定分隔符的文本(如 Web 日志),用正则分组映射表字段:

sql 复制代码
-- 解析 Web 日志的表
CREATE TABLE access_log (
    ip STRING,
    ident STRING,
    user STRING,
    time STRING,
    request STRING,
    status STRING,
    size STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
    -- 正则表达式:分组顺序对应表字段顺序
    "input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) \\[(.*)\\] \"(.*)\" (-|[0-9]*)(-|[0-9]*)",
    -- 可选:输出分隔符(写入时用)
    "output.format.string" = "%1$s %2$s %3$s [%4$s] \"%5$s\" %6$s %7$s"
)
STORED AS TEXTFILE;

场景 3:JSONSerDe ------ 解析 JSON 数据

适配 JSON 格式的半结构化数据:

sql 复制代码
CREATE TABLE json_person (
    id INT,
    name STRING,
    hobby ARRAY<STRING>,
    addr MAP<STRING,STRING>
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
-- 可选:配置 JSON 解析规则(如忽略多余字段)
WITH SERDEPROPERTIES (
    "ignore.malformed.json" = "true",  -- 忽略格式错误的 JSON 行
    "mapping.id" = "user_id"  -- 映射 JSON 中的 user_id 到表的 id 字段
)
STORED AS TEXTFILE;

四、关键注意事项

  1. SerDe 与存储格式匹配
    • TextFile 通常搭配 LazySimpleSerDe/RegexSerDe/JSONSerDe;
    • Parquet/ORC 有专属 SerDe(如 ParquetHiveSerDe),无需手动指定(Hive 自动匹配);
  2. 字段顺序 / 数量匹配
    • RegexSerDe 的正则分组数量必须和表字段数量一致(比如 7 个分组对应 7 个字段);
    • JSONSerDe 的字段名(或映射名)必须和 JSON 中的 Key 匹配;
  3. 性能优先级
    • 列式存储(Parquet/ORC)的 SerDe 性能远高于文本类 SerDe;
    • LazySimpleSerDe 性能 > RegexSerDe(正则解析耗时更高);

Hive参数

命名规则

hive当中的参数、变量,都是以命名空间开头

通过${}方式进行引用,其中system、env下的变量必须以前缀开头。

hive 参数设置方式

**第一种方式:**修改配置文件 ${HIVE_HOME}/conf/hive-site.xml

第二种方式:启动hive cli时,通过--hiveconf key=value的方式进行设置

例如:设置打印输出的时候打印标题行

bash 复制代码
[root@node4 ~]# hive --hiveconf hive.cli.print.header=true
hive> select word,count from wc_count;
OK
word count
andy 3
hello 5
joy 3
mark 1
rose 2
tom 2

第三种方式:进入cli之后,通过使用set命令设置

sql 复制代码
#set查询参数
hive> set hive.cli.print.header;
hive.cli.print.header=false
#查询所有的参数
hive> set;

#set设置参数
hive> set hive.cli.print.header=true;

注意:2和3两种方式设置的参数只在当前会话有效。

hive的历史操作的命令:

sql 复制代码
[root@node4 ~]# ll -a
-rw-r--r-- 1 root root 11590 11月 19 11:07 .hivehistory
# 在当前用户的家目录/root下有一个.hivehistory文件,该文件记录了执行的hive命令:
[root@node4 ~]# vim .hivehistory

hive参数的初始化配置:

在当前用户的家目录的.hivercwen文件,如果没有可以创建一个,添加想要初始化的参数配置:

sql 复制代码
[root@node4 ~]# vim .hiverc
set hive.cli.print.header=true;

Hive视图、公共表达式、索引

视图

和关系型数据库中的普通视图一样,hive也支持视图

特点:

  • 不支持物化视图
  • 只能查询,不能做加载数据操作
  • 视图的创建,只是保存一份元数据,查询视图时才执行对应的子查询
  • view定义中若包含了ORDER BY/LIMIT语句,当查询视图时也进行ORDER BY/LIMIT语句操作,view当中定义的优先级更高
  • view支持迭代视图

语法:

sql 复制代码
-- 创建视图
CREATE VIEW [IF NOT EXISTS] [db_name.]view_name
[(column_name [COMMENT column_comment], ...) ]
[COMMENT view_comment]
[TBLPROPERTIES (property_name = property_value, ...)]
AS SELECT ... ;
--示例
create view v_psn as select * from person order by id desc;

-- 删除视图

DROP VIEW [IF EXISTS] [db_name.]view_name;
--示例
drop view v_psn;

公共表达式(CTE,推荐写法)

CTE 是通过 WITH 子句定义的临时查询结果集,仅在当前 SQL 语句中有效,执行完后自动销毁,相当于 "一次性的临时表",但比临时表更轻量、更易维护。

基础语法

sql 复制代码
WITH cte_name1 AS (
    -- 第一个 CTE 的查询逻辑
    SELECT 列1, 列2 FROM 表 WHERE 条件
),
cte_name2 AS (
    -- 第二个 CTE(可引用前面的 CTE)
    SELECT 列3, 列4 FROM cte_name1 WHERE 条件
)
-- 主查询:引用 CTE
SELECT * FROM cte_name2;

递归 CTE

递归 CTE 是一种能自己调用自己的查询,专门用来处理有层级关系的数据,比如:

  • 公司的部门树(总公司 → 分公司 → 部门 → 小组)
  • 论坛的评论楼(主评论 → 一级回复 → 二级回复)
  • 家谱关系(爷爷 → 爸爸 → 你 → 孩子)

它的核心结构分为两部分:

  • 锚点成员(Anchor Member):查询的 "起点",用来获取层级的根节点。
  • 递归成员(Recursive Member):查询的 "循环体",用当前结果去关联原表,获取下一层节点,直到没有新数据为止。

示例:用 "部门树" 例子一步步拆解

假设我们有一张部门表 dept

dept_id dept_name parent_id
1 总公司 0
2 北京分公司 1
3 技术部 2
4 产品部 2
5 上海分公司 1
6 运营部 5

我们的目标是用递归 CTE 把这棵树的层级关系查出来。

第一步:锚点成员(找根节点)

sql 复制代码
SELECT dept_id, dept_name, parent_id, 1 AS level
FROM dept
WHERE parent_id = 0
  • 这里 parent_id = 0 表示根节点(总公司)。
  • 我们给根节点的层级 level 设为 1
  • 结果:只有 总公司 这一行。

第二步:递归成员(找子节点)

sql 复制代码
SELECT d.dept_id, d.dept_name, d.parent_id, dt.level + 1 AS level
FROM dept d
JOIN dept_tree dt ON d.parent_id = dt.dept_id
  • 这是递归的核心:我们把上一步得到的临时结果 dept_tree(当前层级)和原表 dept 关联,找到所有 parent_id 等于当前 dept_id 的子节点。
  • 子节点的层级是父节点层级 + 1(比如总公司是 1,它的子节点北京分公司就是 2)。
  • 第一次递归:用根节点 总公司(dept_id=1) 找到子节点 北京分公司上海分公司(层级 2)。
  • 第二次递归:用 北京分公司(dept_id=2) 找到子节点 技术部产品部(层级 3);用 上海分公司(dept_id=5) 找到子节点 运营部(层级 3)。
  • 第三次递归:子节点 技术部产品部运营部 没有子节点了,递归结束。

第三步:组合起来

把锚点成员和递归成员用 UNION ALL 连接,就构成了完整的递归 CTE:

sql 复制代码
WITH RECURSIVE dept_tree AS (
    -- 锚点成员:根节点
    SELECT dept_id, dept_name, parent_id, 1 AS level
    FROM dept
    WHERE parent_id = 0

    UNION ALL

    -- 递归成员:找子节点
    SELECT d.dept_id, d.dept_name, d.parent_id, dt.level + 1 AS level
    FROM dept d
    JOIN dept_tree dt ON d.parent_id = dt.dept_id
)
SELECT * FROM dept_tree;

递归 CTE 的执行流程

  • 先执行锚点成员,得到根节点结果集,作为第一次递归的输入。
  • 执行递归成员,用输入结果集关联原表,得到子节点结果集。
  • 把递归成员的结果集作为新的输入,再次执行递归成员。
  • 重复步骤 2-3,直到递归成员不再返回新的结果集,递归结束。
  • 最后用 UNION ALL 把所有结果集合并,得到最终的层级关系。

索引

索引在Hive 3.0+ 已弃用。Hive 官方推荐使用 分区(Partitioning)分桶(Bucketing)列式存储(ORC/Parquet) 替代索引。

Hive运行方式

命令行方式cli (控制台模式,了解即可)

与hdfs交互:

sql 复制代码
hive> dfs -ls /; Found 7 items
Found 5 items
drwxr-xr-x   - root supergroup          0 2026-01-17 04:53 /fof
drwx------   - root supergroup          0 2026-01-18 11:29 /tmp
drwxr-xr-x   - root supergroup          0 2026-01-18 14:52 /user
drwxr-xr-x   - root supergroup          0 2026-01-16 17:22 /weather
drwxr-xr-x   - root supergroup          0 2026-01-15 13:57 /wordcount
hive> dfs -cat /user/hive_remote/warehouse/psnbucket/000000_0;
8,scala,88
4,hive,44

Linux 交互:!开头

sql 复制代码
!pwd;
!ls /root;

脚本运行方式(实际生成环境中更为常用)

sql 复制代码
[root@node4 ~]# hive --service cli --help usage: hive
-d,--define <key=value>          Variable substitution 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 执行后面跟着的sql语句
-f <filename>                    SQL from files 执行指定文件中的sql语句
-H,--help                        Print help information
--hiveconf <property=value>   Use value for given property
--hivevar <key=value>         Variable substitution to apply to Hive
commands. e.g. --hivevar A=B
-i <filename>                    Initialization SQL file 执行初始化的sql文件
-S,--silent                      Silent mode in interactive shell 静默模式(不显示Ok和Time taken信息)
-v,--verbose                     Verbose mode (echo executed SQL to the console)

示例:

sql 复制代码
[root@node4 ~]# hive -e "select * from person"
person.id   person.name person.likes    person.address
1   小明1 ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}
2   小明2 ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}
3   小明3 ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}
4   小明4 ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}
5   小明5 ["lol","movie"] {"beijing":"xisanqi","shanghai":"pudong"}
6   小明6 ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}
7   小明7 ["lol","book"]  {"beijing":"xisanqi","shanghai":"pudong"}
8   小明8 ["lol","book"]  {"beijing":"xisanqi","shanghai":"pudong"}
9   小明9 ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"} 

#将查询结果写入到指定的文件中
[root@node4 ~]# hive -e "select * from person" >he.log
#查看写入后的文件
[root@node4 ~]# cat he.log

hive脚本: ./脚本名称

sql 复制代码
[root@node4 ~]# vim hive.sh
hive -e "select * from person"
[root@node4 ~]# chmod +x hive.sh [root@node4 ~]# ./hive.sh

hive -f file:执行后还在linux命令行

sql 复制代码
[root@node4 ~]# vim hivef.sql select * from person
[root@node4 ~]# hive -f hivef.sql

hive -i init.sql:执行后进入hive客户端

sql 复制代码
[root@node4 ~]# hive -i init.sql

在hive cli中运行一个sql脚本:

sql 复制代码
hive> source hivef.sql;

Hive优化

Fetch 抓取

Fetch抓取是指Hive在对某些查询操作可以不必使用MapReduce计算,只需要读取指定表对应存储目下的文件,然后输出查询结果到控制台即可。

在hive-default.xml.template文件中hive.fetch.task.conversion,默认值是more。

set hive.fetch.task.conversion=none/minimal/more(默认值);

默认做了优化,以下两种情况都不经过mr,改为 none后,将走mr。

以下SQL不会转为Mapreduce来执行

  1. select仅查询本表字段

  2. where仅对本表字段做条件过滤

  3. 使用limit

本地运行模式

开发和测试阶段使用本地模式,优点快,缺点是http://node3:8088/cluster看不到。对于小数据集hive通过本地模式在单机上处理任务,执行时间可以明显被缩短。

sql 复制代码
# 开启本地模式,默认为false
hive> set hive.exec.mode.local.auto=true;

设置local mr 的最大输入数据量,当输入数据量小于这个值是采用local mr的方式,默认134217728也就是128M。若大于该配置仍会以集群方式来运行!

hive.exec.mode.local.auto.inputbytes.max=134217728

设置local mr 的最大输入文件个数,当输入文件个数小于这个值是采用local mr方式

hive.exec.mode.local.auto.input.files.max=4 #默认4

并行模式

sql 复制代码
# 修改为并行执行,默认为false
hive>set hive.exec.parallel=true;

hive> set hive.exec.parallel.thread.number; 
hive.exec.parallel.thread.number=8
#并行进程默认是8个进程同时进行。

严格与非严格模式

| 模式 | 适用场景 |
| 严格模式 | 生产环境(强制规范查询写法,避免误操作导致集群资源耗尽、查询超时) |

非严格模式(默认) 测试 / 开发环境(灵活调试查询,无需严格遵守过滤规则,提升开发效率)

严格模式的核心限制

  1. 限制分区表的全表扫描
  • 规则 :查询分区表时,WHERE 子句必须包含分区列的过滤条件,否则直接报错。
  1. 限制 ORDER BY 不加 LIMIT
  • 规则ORDER BY 必须配合 LIMIT 使用,否则报错。
  1. 限制笛卡尔积查询
  • 规则 :两个表关联时,必须指定 JOIN 条件,禁止隐式笛卡尔积。
sql 复制代码
hive> set hive.mapred.mode=strict;#严格模式
hive> set hive.mapred.mode=nostrict;#非严格模式

行列过滤

行列过滤也被称为分区剪裁和列裁剪。

尽可能早的过滤掉尽可能多的数据,避免大量数据流入外层sql

行过滤

  • a. 分区在hive上本质是目录,分区剪裁可以高效的过滤掉大部分数据。
  • b. 尽量使用分区剪裁。
  • c. where条件过滤

列过滤(列裁剪)

  • a.只获取需要的列的数据,减少数据输出。
  • b.少用select *

JVM 重用

为什么需要 JVM 重用?

Hive 执行 MapReduce 任务时,默认会为每个 Map/Reduce 任务启动一个独立的 JVM 进程:

  • 问题:创建和销毁 JVM 进程会消耗大量系统资源(CPU / 内存),尤其是当任务包含大量小 Map/Reduce 任务时(比如查询小文件多的表),JVM 启停开销会成为性能瓶颈。
  • 解决思路 :JVM 重用允许一个 JVM 进程重复执行多个 Map/Reduce 任务,避免频繁启停,降低资源开销。

核心逻辑

启用 JVM 重用后,一个 JVM 进程会被分配一个 "任务池",执行完一个任务后不销毁,而是继续执行池中的下一个任务,直到达到最大重用次数或任务池为空,才销毁 JVM。

适用场景

  1. 小文件多的场景:查询包含大量小文件的表时,会生成大量小 Map 任务,JVM 重用能大幅减少启停开销;
  2. 短任务密集的场景:如简单的过滤、聚合查询,任务执行时间短,JVM 启停占比高;
  3. 集群资源充足的场景:JVM 重用会占用更多内存(JVM 进程不销毁),需确保集群有足够内存。

配置方式

sql 复制代码
-- 开启 JVM 重用(默认 false)
set mapred.job.reuse.jvm.num.tasks = 10;  -- 一个 JVM 最多重用 10 次

-- 可选:设置 JVM 等待下一个任务的超时时间(默认 10000 毫秒)
set mapred.job.reuse.jvm.waitmillis = 20000;

全局级配置(修改 mapred-site.xml,重启集群生效)

sql 复制代码
<property>
    <name>mapred.job.reuse.jvm.num.tasks</name>
    <value>10</value>
    <description>每个 JVM 最多重用的任务数</description>
</property>
<property>
    <name>mapred.job.reuse.jvm.waitmillis</name>
    <value>20000</value>
    <description>JVM 等待下一个任务的超时时间</description>
</property>

推测执行

为什么需要推测执行?

Hive 执行一个查询会拆分成多个 Map/Reduce 任务,这些任务理论上并行执行且耗时相近。但在实际集群中,可能因为以下原因出现慢任务

  • 某台节点的 CPU / 内存 / 磁盘 IO 资源被抢占;
  • 节点网络波动,数据传输慢;
  • 任务分配到的数据分片不均匀(比如个别分片数据量极大)。

这些慢任务会成为整个 Job 的 "瓶颈"------ 即使其他 99% 的任务都完成了,Job 也必须等待最后 1% 的慢任务结束。

推测执行的工作流程

  1. 任务监控:集群会监控所有并行任务的执行进度和耗时;
  2. 慢任务判定:当大部分任务(比如 90%)已经完成,剩下的少数任务耗时远超平均耗时(比如超过 1.5 倍平均耗时),则判定这些任务为 "慢任务";
  3. 启动备份任务 :为慢任务启动一个备份任务,与原任务并行执行;
  4. 结果抢占:哪个任务先执行完成,就将其结果作为最终结果,并立即终止另一个未完成的任务;
  5. 结果合并:采用成功任务的结果,继续推进整个 Job。

配置

sql 复制代码
set hive.mapred.reduce.tasks.speculative.execution=true;#开启推测执行

表优化

小表与大表join

Reduce side join是非常低效的,因为shuffle阶段要进行大量的数据传输。所以有Map side join针对小表与大表join进行优化。两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多 份,让每个map task内存中存在一份(比如存放到hash table中),然后只扫描大表:对于大表中的每一条记录key/value,在hash table中查找是否有相同的key的记录,如果有,则连接后输出即可。

实现方式:

1、SQL方式,在SQL语句中添加MapJoin标记(mapjoin hint)

sql 复制代码
SELECT  /*+ MAPJOIN(smallTable) */  smallTable.key,  bigTable.value
FROM  smallTable  JOIN  bigTable  ON  smallTable.key  =  bigTable.key;

2、开启自动的MapJoin

hive.ignore.mapjoin.hint;默认为true,如果自动和手动冲突了,手动的配置失效,以自动配置为准。

sql 复制代码
hive> set hive.ignore.mapjoin.hint;
hive.ignore.mapjoin.hint=true

相关配置参数:

  1. hive.mapjoin.smalltable.filesize; #默认25M

(大表小表判断的阈值,如果表的大小小于该值则会被加载到内存中运行)

  1. hive.ignore.mapjoin.hint;

(默认值:true;是否忽略mapjoin hint 即mapjoin标记)

  1. hive.auto.convert.join.noconditionaltask;

(默认值:true;将普通的join转化为普通的mapjoin时,是否将多个mapjoin转化为一个mapjoin)

  1. hive.auto.convert.join.noconditionaltask.size;

(将多个mapjoin转化为一个mapjoin时,其表的最大值)

扩展 :hive.groupby.skewindata 避免数据倾斜。是 Hive 针对 GROUP BY 语句数据倾斜的专项优化开关。 当开启该参数时,Hive 会将原本的 "1 轮 MapReduce" 的 GROUP BY 拆成 2 轮MapReduce ,打散倾斜的 Key,避免单个 Reduce 任务处理过多数据;比如:按 gender分组,若 "男" 的记录有 1 亿条,"女" 只有 100 万条 → 处理 "男" 的 Reduce 卡死,其他 Reduce 很快完成。此时落开启则原本 1 个 Reduce 处理 1 亿条 "男" 的数据,变成 10 个 Reduce 各处理 1000 万条,再汇总,彻底解决倾斜。

大表join大表

  1. 空key过滤:

(1) 有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer

上,从而导致内存不够。此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数

是异常数据,我们需要在SQL语句中进行过滤。最终目的是reduce负载均衡,防止数据倾斜。不过一般在ETL数据清洗时便会对空值进行处理(过滤掉或者赋值)。

  1. 空key转换:

有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果

中,此时我们可以表a中key为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的

reducer上。

Map-Side 聚合

相当用combiner。

  1. 默认情况下,Map阶段相同key发送到一个reduce,当某个key的数据过大时就会发生数据倾斜。

  2. 并不是所有的聚合都需要再reduce端完成,可以先在map端进行聚合,最后再在reduce端聚合。 如同combiner。

  3. 通过设置以下参数开启在Map端的聚合

#开启map端的聚合

set hive.map.aggr=true;

#相关参数:

hive.groupby.mapaggr.checkinterval;

map端group by执行聚合时处理的多少行数据(默认:100000)

hive.map.aggr.hash.min.reduction;

进行聚合的最小比例(预先对100000条数据做聚合,这100000条数据的体积若聚合之后的数据量/聚合

前的值大于该配置0.5,则不会聚合)

hive.map.aggr.hash.percentmemory;

map端聚合使用的内存的最大值

hive.map.aggr.hash.force.flush.memory.threshold;

map端做聚合操作是hash表的最大可用内存,大于该值则会触发flush

hive.groupby.skewindata

是否对GroupBy产生的数据倾斜做优化,默认为false

去重统计

数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换。

每个reduce任务处理的数据量,默认值256MB

set hive.exec.reducers.bytes.per.reducer=256000000

sql 复制代码
select count(distinct imei) from jizhan;
#转换为
Select count(imei) from (select imei from jizhan group by imei) tmp

虽然会多一个Job来完成,但在数据量大的情况下,这个绝对值得。

合理设置 Map Reduce 数量

合理设置Map数

通常情况下,作业会通过计算split切片的数量决定产生对应个数map任务。 主要决定因素:input的文件总个数,input的文件大小,集群设置的文件块大小。block块,split_size, 文件个数 split切片数量决定map task数量。

思考一:是不是 map 数越多越好?

答:不是。如果一个任务有很多小文件,则每个小文件都会被当成一个split切片,用一个map任务来完成,执行真实业务逻辑运算的时间远远小于map任务的启动和初始化的时间,就会造成很大的资源浪费。另外,同时可执行的map数也是受限的。如何优化,答案是减少map的数量,比如通过合并小文件减少map数量。

思考二:是不是保证每个 map 处理接近 128M 的文件块,就高枕无忧了?

答:不一定,比如一个128MB(或者接近该值)的文件,默认情况会用一个map去完成,但是这个文件可能只有很少的小字段,却又几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定比较耗时。如何解决?答案是增加map的个数。

合理设置 Reduce

reduce个数并不是越多越好,过多的启动和初始化reduce也会消耗时间和资源;另外过多的

reduce会生成很多个结果文件,同样产生了小文件的问题。

相关推荐
B站计算机毕业设计超人3 天前
计算机毕业设计Django+Vue.js高考推荐系统 高考可视化 大数据毕业设计(源码+LW文档+PPT+详细讲解)
大数据·vue.js·hadoop·django·毕业设计·课程设计·推荐算法
B站计算机毕业设计超人3 天前
计算机毕业设计Django+Vue.js音乐推荐系统 音乐可视化 大数据毕业设计 (源码+文档+PPT+讲解)
大数据·vue.js·hadoop·python·spark·django·课程设计
tryCbest3 天前
数据库SQL学习
数据库·sql
十月南城3 天前
数据湖技术对比——Iceberg、Hudi、Delta的表格格式与维护策略
大数据·数据库·数据仓库·hive·hadoop·spark
王九思3 天前
Hive Thrift Server 介绍
数据仓库·hive·hadoop
cowboy2583 天前
mysql5.7及以下版本查询所有后代值(包括本身)
数据库·sql
努力的lpp3 天前
SQL 报错注入
数据库·sql·web安全·网络安全·sql注入
麦聪聊数据3 天前
统一 Web SQL 平台如何收编企业内部的“野生数据看板”?
数据库·sql·低代码·微服务·架构
山峰哥3 天前
吃透 SQL 优化:告别慢查询,解锁数据库高性能
服务器·数据库·sql·oracle·性能优化·编辑器
Asher05093 天前
Hive核心知识:从基础到实战全解析
数据仓库·hive·hadoop