一、自定义过hiveudf函数吗?hive中的udf函数有几种?
UDF(User-Defined Function)是 Hive 中允许用户扩展内置函数的机制,通过编写自定义代码实现特定的数据处理逻辑。与 SQL 内置函数(如 SUM
、SUBSTRING
)不同,UDF 可以实现更灵活、复杂的功能。
Hive 支持三种 UDF:
UDF(普通函数):输入一行,输出一行(一对一,比如将字符串转成大写)。
UDAF(聚合函数):输入多行,输出一行(多对一,比如计算一组数字的平均值)。
UDTF(表生成函数):输入一行,输出多行(一对多,比如按逗号分割拆分字符串,一行转多行
)
。
二、hive的几种建表方式
hive创建表有几种方式,其区别是什么?
1)create table
这是最基础的建表方式,需要手动指定表的列名、数据类型、存储格式等结构信息,并且不会自动填充数据。如果要填充数据,后续需要通过INSERT INTO
、LOAD DATA
或 HDFS PUT
等操作。
2)create table as select...
该方式会根据SELECT
语句的查询结果创建一个新表,并将查询结果数据填充到新表中。新表的列名和数据类型会根据SELECT
语句中的字段自动推断。
3)create table like tablename1;
这种方式会创建一个新表,新表的结构(包括列名、数据类型、分区、分桶等定义)与指定的已存在表完全相同,但不会复制已存在表中的数据。后续如果需要填充数据,同样需要使用INSERT INTO
、LOAD DATA
等操作。
不同方式的区别
1)create table 创建表,需要明确指定表结构和索引;
2)create table as 创建表,只有表结构,没有索引;
3)create table like 创建表,创建出来的新表包含源表的完整结构及索引信息;
建表方式 | 是否需要手动指定结构 | 是否复制数据 | 灵活性 | 适用场景 |
---|---|---|---|---|
create table |
是,需详细指定 | 否,需后续手动填充 | 高,可精细控制表结构、存储格式等 | 已知表结构,对表结构有精细控制需求 |
create table as select... |
否,根据查询结果自动推断 | 是,根据查询结果填充数据 | 中,存储格式依赖于源表 | 基于已有数据查询结果快速创建新表 |
create table like tablename1 |
否,复制已有表结构 | 否,需后续手动填充 | 中,结构固定但可灵活填充数据 | 快速创建与已有表结构相同的新表 |
三、数据库中的NULL在hive中如何存储?
简要描述数据库中的null,说出null在hive底层如何存储?
并解释select a.* from t1 a left outer join on t2 b on a.id = b.id where b.id is null;语句的含义?
在数据库中,NULL
代表缺失值或未知值,它和空字符串(""
)、零值(例如数值类型中的 0
)是不同的概念。
空字符串:是一个确定的、有长度为 0 的字符数据。
零值:是具体数据类型(如整型、浮点型等)中的一个确定数值。
NULL
:表示数据未知、未赋值或者不存在,它参与运算时,会使结果也通常为 NULL
。
hive表中默认将NULL存为\N
表t1别名是a,表t2别名是b,根据id字段做左外连接,查询出b.id为null的值
四、collect_list()和collect_set的区别(行转列)
hive中,collect_list(),collect_set()两个函数的区别是什么?参数类型有什么限制?
hive中collect相关的函数有collect_list和collect_set,它们都是将分组中的某列转为一个数组相返回,不同的是collect_list不去重,而collect_set去重
collect_list(col)函数将分组内指定列的所有值按原始顺序保留重复值,聚合为一个数组,只接受基本数据类型,它的主要作用是将某字段的值进行汇总,产生array类型字段
特点:保留重复元素,维持元素在原始数据中的顺序
collect_set(col)函数将分组内指定列的所有值去重后,聚合为一个无固定顺序的数组,只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段
特点:自动去除重(相同值只保留一个)元素顺序不固定(无法保证与原始数据顺序一致)
五、hive查询内存溢出如何解决
hive在select查询数据后,执行insert操作插入ORC表和parquet表操作的过程中,遇到over gclimit、java.lang.OutMemoryError:java heap space等字样的错误,大概从那些地方查找原因解决问题?
1)可能数据分布不均匀造成的,可以在select阶段加cluster by rand()让数据均匀分布
2)map和reduce阶段的内存不够,通过hive参数增加内存
set mapreduce.reduce.memory.mb=16384;(实际调试的时候,8G内存不够,增加到16G解决问题)表示每个 Reduce 任务最多可使用 16GB 内存
set mapreduce.map.memory.mb = 4096;表示每个 Map 任务最多可使用 4GB 内存
3)另外在数据格式不统一的情况下,不同格式的insert 操作效率奇低
六、hive 4种by操作的区别与联系(重点)
hive中order by 、distribute by 、sort by 和cluster by的区别和联系?
order by 会对数据进行全局排序,和oracle 和 mysql等数据库中的order by 效果一样,它只在一个reduce中进行,所以数据量特别大的时候效率非常低。而且当设置:set hive.mapred.mode=strict的时候不指定limit,执行select会报错,如下:LIMIT must also be specified.
sort by是单独在各自的reduce中进行排序,所以并不能保证全局有序,一般和distribute by一起执行,而且distribute by 要写在sort by 前面,如果mapred.reduce.tasks=1和order by效果一样,如果大于1会分成几个文件输出每个文件会按照指定的字段排序,而不保证全局有序。sort by不受hive.mapred.mode是否为strict,nostrict的影响。mapred.reduce.tasks=1
是强制指定 1 个 Reduce 任务处理数据,适用于需要全局汇总或结果合并为单个文件的场景。
distribute by 会对指定的字段按照hashCode值对reduce的个数取模,然后将任务分配到对应的reduce中去执行,也就是在mapreduce程序中的patition分区过程。默认根据指定key.hashCode()$lnteger.MAX_VALUE%numReduce确定处理该任务的reduce。
cluster by distribute by 和sort by 合用就相当于cluster by,但是cluster by不能指定排序为asc或desc的规则,只能是desc倒序排列
七、hive性能调优
详细的在我的上一篇文章hive的相关的优化
hive性能调优的常见方法?
1、hive层面优化
1)利用分区表优化
2)利用分桶表优化
3)join优化
4)Group By数据倾斜优化解决这个问题的方法是配置一个参数:set hive.groupby.skewindata=true
当group by
的 Key 分布不均(某 Key 对应数据量极大)时,设置set hive.groupby.skewindata=true
后,Hive 会将查询拆分为两次 MapReduce:第一次随机分发数据并局部聚合,第二次按原 Key 聚合,避免单 Reduce 处理过多数据。
5)Order By优化
Order By
会将所有数据发送到一个 Reduce 进行全局排序,效率低;
替代方案:用Sort By
(每个 Reduce 内排序)+Distribute By
(按指定列分发到不同 Reduce),实现局部有序,提升效率;若需全局有序,可结合Limit
限制返回条数,减少排序数据量
6)一次读取多次插入
7)join字段显示类型转换
若两表 Join 的字段类型不一致(如一个是string
,一个是int
),需显式转换为相同类型(如cast(col as string)
),避免 Hive 隐式转换导致的全表扫描或数据不匹配
2、hive架构层面优化
1)不执行MapReduce
对于简单查询(如select * from table limit 10
),通过set hive.fetch.task.conversion=more
让 Hive 直接读取数据文件返回结果,跳过 MapReduce 阶段,提升响应速度。
2)本地模式执行MapReduce
小数据集查询时,开启本地模式(set hive.exec.mode.local.auto=true
),让 MapReduce 任务在单节点本地执行,避免集群资源调度开销,加速小任务运行(默认适用于数据量小于 128MB、Map 数小于 4 的任务)。
3)JVM重(chong)用
通过set mapreduce.job.jvm.numtasks=N
(N 为整数)设置一个 JVM 实例可执行的 Map/Reduce 任务数,减少 JVM 启动和销毁的开销(尤其适合小文件多、任务数量多的场景)
4)并行化
对于包含多个独立子查询(如union all
、多表插入)的 SQL,设置set hive.exec.parallel=true
和set hive.exec.parallel.thread.number=N
(N 为并行线程数),让子查询并行执行,缩短总耗时。
3、底层MapReduce优化
1)合理设置map数
避免 map 数过多:小文件过多时,通过CombineHiveInputFormat
合并小文件(set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
),减少 map 数,降低资源调度开销;
避免 map 数过少:大文件拆分时,通过mapreduce.input.fileinputformat.split.minsize
和mapreduce.input.fileinputformat.split.maxsize
调整 split 大小,确保每个 map 处理的数据量适中(通常 128MB~1GB)。
2)合理设置Reduce数
手动指定:通过set mapreduce.job.reduces=N
(N 为 Reduce 数)设置,通常根据数据量(每个 Reduce 处理 1~2GB 数据)或集群资源调整;
自动调整:开启hive.exec.dynamic.partition=true
和hive.exec.dynamic.partition.mode=nonstrict
,让 Hive 根据数据量动态计算 Reduce 数,避免 Reduce 数过多(资源浪费)或过少(数据倾斜)
八、hive包含哪些join操作
hive的join有几种方式,怎么实现join的?
1、hive中常见的join方式
hive中除了支持和传统数据库中一样的内关联、左关联、右关联、全关联、还支持left semi join和cross join,但这两种join类型也可以用前面的代替
2、如何实现join?
1)内关联(join)只返回能关联上的结果,select a.id,a.name,b.age from djt_a a join djt_b b on (a.id = b.id);
2)左外关联(left [outer] join)以left [outer] join关键字前面的表作为主表,和其他表进行关联,返回记录和主表的记录数一致,关联不上的字段设置为NULL。是否指定outer关键字,对查询结果无影响。
select a.id,a.name,b.age from djt_a left join djt_b b on (a.id = b.id);
3)右外关联(right [outer] join)和左外关联相反,以right [outer] join 关键词后面的表作为主表,和前面的表做关联,返回记录数和主表一致,关联不上的字段为NULL。是否指定outer关键字,对查询结果无影响;
4)全外关联(full [outer] join)以两个表的记录为基准,返回两个表的记录去重之和,关联不上的字段为NULL。是否指定outer关键字无影响,注意:full join时候,hive不会使用Mapjoin来优化;
5)left semi join以left semi join关键字前面的表为主表,返回主表的key也在副表中的记录
left semi join与left join的区别?(重点)
left semi join(左半连接)是in/exists子查询的一种更高级的实现。
left join
:以左表为主表,返回左表所有记录 + 右表中匹配关联条件的记录;右表无匹配时,用 NULL
填充。
left semi join
:仅返回左表中与右表存在匹配关系的记录(类似 in
或 exists
子查询),且只保留左表字段。
1、left semi join join子句中右边的表只能在on子句中设置过滤条件;
2、left semi join中最后的select的结果只许出现左表;
3、因为left semi join是in(keySet)的关系,遇到右表重复记录,左表会跳过,仅仅只返回一条记录,而join则会一直遍历。
6)笛卡尔积关联(cross join)返回两个表的笛卡尔积结果,不需要指定关联键
九、hive内部表和外部表
hive内部表和外部表的区别?应该如何选择使用哪种表呢?
1)hive向内部表导入数据时,会将数据移动到数据仓库指向的路径;若是外部表,数据的具体存放目录由用户建表时指定,在导入数据到外部表,数据并没有移动到自己的数据仓库目录下,也就是说外部表中的数据并不是由它自己来管理的!而内部表则不一样
2)在删除内部表的时候,hive将会把属于表的元数据和数据全部删掉;而删除外部表的时候,hive仅仅删除外部表的元数据,数据是不会删除的!那么,应该如何选择使用哪种表呢?在大多数情况没有太多的区别,因此选择只是个人喜好的问题。但是如果所有处理都需要由hive完成,那么你应该创建内部表,否则使用外部表!外部表相对来说更加安全些,数据组织也更加灵活,方便共享元数据