基础知识
为什么需要 Hive
Hadoop 生态系统的出现,为以合理的成本处理大数据集提供了一个解决方案,它基于 HDFS(分布式文件系统)实现了一个 MapReduce 编程模型,将计算任务分散到多个硬件机器上,从而降低成本并提供水平伸缩性。
但是从现有的数据基础架构转移到 Hadoop 以及从 Hadoop 中获取数据是一个比较麻烦的事情(MapReduce Java API),Hive 的出现就是为了解决这个问题,基于 Hive 可以方便的实现结构化数据到 Hadoop 数据仓库的数据转移。
Hive 将大多数的查询转化成 MR 任务,HiveQL 既降低了使用难度,也提高了 Hadoop 的扩展性。
Hive 的局限
- Hive 适用于数据不经常变动,而且不需要立即得到查询结果的情况。
- 由于 Hadoop 和 HDFS 的设计,Hive 不支持行级别的插入、删除及更新,不支持事务。
- HiveQL 不符合 ANSI SQL 标准,很多 SQL 和 Oracle、MySQL 存在差异。
Java 和 Hive :词频统计算法
这是《Hadoop权威指南》中的第一章的例子程序,使用 Hadoop Java API 实现一个统计文本文件中每个单词出现次数的程序,可以帮助理解 MR 原理以及使用 Hive 的好处。
关键代码如下:
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.2.2</version>
</dependency>
</dependencies>
package im.yuki.wordcount;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
/**
* @author longkun
* @version V1.0
* @date 2022/3/17 11:36 PM
* @description hadoop 词频统计
*/
public class WordCount {
private static final String OUTPUT_PATH = "hdfs://127.0.0.1:9000/hdp/0317/wordcountoutput/";
public static class Map extends Mapper<LongWritable, Text, Text, LongWritable> {
private static final LongWritable one = new LongWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] words = value.toString().split(" ");
Text word;
for (String w : words) {
word = new Text(w);
context.write(word, one);
}
}
}
public static class Reduce extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException,
InterruptedException {
int count = 0;
for (LongWritable value : values) {
count += value.get();
}
context.write(key, new LongWritable(count));
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 设置环境变量 HADOOP_USER_NAME
System.setProperty("HADOOP_USER_NAME", "longkun");
// 读取配置文件
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS", "hdfs://127.0.0.1:9000");
configuration.set("yarn.resourcemanager.hostname", "hdp01");
FileSystem fileSystem = FileSystem.get(configuration);
Job job = Job.getInstance(configuration, "WordCount");
job.setJarByClass(WordCount.class);
job.setMapperClass(Map.class);
job.setCombinerClass(Reduce.class);
job.setReducerClass(Reduce.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputKeyClass(LongWritable.class);
job.setNumReduceTasks(2);
Path outputPath = new Path(OUTPUT_PATH);
FileInputFormat.setInputPaths(job, new Path("hdfs://127.0.0.1:9000/hdp/0317/wordcountinput/"));
FileOutputFormat.setOutputPath(job, outputPath);
if (fileSystem.exists(outputPath)) {
fileSystem.delete(outputPath, true);
}
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
⚠️ 运行时会提示 log4j 的配置有误,运行程序前需要将 $HADOOP_HOME/etc/hadoop/log4j.properties 文件复制到 src/main/resouces 目录下。
将需要统计的文本文件上传到 hdfs://127.0.0.1:9000/hdp/0317/wordcountinput 目录下。
在 Hive 中统计词频:
1、将文本文件上传到 hdfs 中
hdfs dfs -put ~/Desktop/wordcount.txt /hdp/0317/wordcountinput
2、将 hdfs 中的数据插入到 Hive 表中
> load data inpath '/hdp/0317/wordcountinput/wordcount.txt' docs
3、HiveQL 查询结果
select tmp.word, count(*) as cnt
from (
select explode(split(line, ' ')) as word
from docs
) tmp
group by tmp.word
order by cnt;
Hive 命令
执行 hive --help
查看 Hive 命令列表:
选项 | 名称 | 描述 |
---|---|---|
cli | 命令行界面 | 进入命令行。 |
hwi | Hive Web 界面 | 可以执行查询语句和其他命令的简单 Web 界面。 |
metastore | 启动一个扩展的元数据服务,可以供多客户端使用。 | |
rcfilecat | 一个可以打印出 RCFile 格式文件内容的工具 |
CLI 选项
使用命令 hive --help --service cli
查看 cli 选项。
参数 | 含义 |
---|---|
-d | –define | 变量替换 |
-e | 执行命令行中的 SQL |
-f | 从文件中执行 SQL |
-H | 打印帮助信息 |
-h | 连接主机名 |
-i | 初始化 SQL 文件 |
-p | 连接端口 |
-S | -silent | 交互式命令行下安静模式 |
-v | –verbose | 输出调试信息 |
Hive 的属性命名空间
命名空间 | 权限 | 描述 |
---|---|---|
hivevar | 可读可写 | 用户自定义变量 |
hiveconf | 可读可写 | Hive 相关的配置 |
system | 可读可写 | Java 定义的配置属性 |
env | 只可读 | Shell 环境定义的环境变量 |
几个例子🌰:
# hivevar --define & set
$ hive --define foo=bar;
> set foo;
> foo=bar;
> set hivevar:foo=bar2;
> create table tbl_0318(int i, ${foo} string);
> desc tbl_0318;
OK
i int
bar2 string
# hiveconf
# 显示当前所在库名
> set hiveconf hive.cli.print.current.db=true;
# system
> set system:user.name
system:user.name=longkun
# env
> set env:HOME
env:HOME=/Users/longkun
Hive 中使用一次命令
✅ 如果希望一次执行多个查询,查询结束后立即退出 cli,可以使用 -e 选项:
$ hive --service cli -e "select * from db_0316.docs where 1 = 1";
✅ 还可以将输出重定向到一个文件中:
$ hive --service cli -e "select * from db_0316.docs where 1 = 1" > ~/Desktop/hive_tmp_result.txt
✅ 当记不清楚某个属性名时,可以使用 grep :
$ hive -S -e "set" | grep current.db
hive.cli.print.current.db=false
$ hive -S -e "set" | grep warehouse
hive.metastore.warehouse.dir=/user/hive/warehouse
从文件中执行查询
可以使用 -f 选项从文件中执行一个或多个查询语句,文件尽量使用 .q 或者 .hql 后缀。
新建一个文本文件 query.hql:
select *
from db_0316.docs
where 1 = 1;
# 执行查询
$ hive -S -f query.hql
# 在 cli 中可以使用 source 命令来执行文件中的查询语句
> source ~/Documents/Hive/query.hql
hiverc文件
-i 选项执行一个文件,每次 CLI 启动时会先执行这个文件。Hive 会在当前目录下寻找 .hiverc 文件并执行。编辑 $HIVE_HOME/.hiverc 文件,添加几个比较实用的变量(⚠️ 分号是必须的):
set hive.cli.print.current.db=true;
set hive.cli.print.header=true;
set hive.exec.mode.local.auto=true;
✅ 使用 tab 键可以补全关键字或者函数名。
执行 shell 命令
无需退出 cli 即可执行简单的 shell 命令,只需要在 shell 命令前加上 ! ,并且以 ; 结尾。
hive (default)> !pwd;
/Users/longkun
在 Hive 内使用 dfs 命令
用户可以在 cli 中执行 Hadoop 的 dfs 命令,只需要将 hdfs 去掉。
hive (default)> dfs -ls /;
Found 3 items
drwxr-xr-x - longkun supergroup 0 2022-03-17 23:54 /hdp
drwx-wx-wx - longkun supergroup 0 2022-03-18 00:52 /tmp
drwxr-xr-x - longkun supergroup 0 2022-03-16 21:50 /user
据说这种方式比在 bash shell 中执行 hdfs dfs … 更高效,因为后者会每次启动一个 JVM 实例,而 Hive 会在同一个进程执行。
数据类型和文件格式
byte、Byte、bit、字节
bit
bit 即是位,表示一个二进制位,0 或 1。
byte
Java 的基本数据类型之一,存储整形,Byte 是其包装类。
Byte
Byte 表示字节,1 Byte = 8 bit
Hive 中的数据类型都来源于 Java 中的数据类型。
Hive 中的数据类型
数据类型 | 长度 | 例子🌰 |
---|---|---|
TINYINT | 1byte 有符号整数 | 20 |
SMALLINT | 2byte 有符号整数 | 20 |
INT | 4byte 有符号整数 | 20 |
BIGINT | 8byte 有符号整数 | 20 |
BOOLEAN | bool类型,true 或者 false | TRUE |
FLOAT | 单精度浮点型 | 3.1315 |
DOUBLE | 双精度浮点型 | 3.1415 |
STRING | 字符序列,可以使用单引号或者双引号 | ‘zhang san’ “wang er” |
TIMESTAMP | 整数、浮点或者字符串 | Unix新纪元秒,Unix新纪元秒及纳秒,JDBC时间格式 |
BINARY | 字节数组 | 和关系型数据库中 VARNIBARY类似?没看懂 |
单精度和双精度是什么意思?单和双是什么意思?
单精度:1位符号,8位指数,23位小数。
双精度:1位符号,11位指数,52位小数。
还是没解释 单 和 双 的意思。。
集合类型
Hive 中支持 struct、map 和 array 集合数据类型。
数据类型 | 描述 | 示例 |
---|---|---|
STRUCT | 与对象类似,可以通过 . 访问元素内容 | struct{first string, last string} |
MAP | 键值对 | map(‘first’, ‘john’, ‘last’, ‘doe’) |
ARRAY | 具有相同类型的变量集合 | array(‘first’, ‘last’) |
建表语句:
drop table if exists db_0320.tbl_person;
drop table if exists db_0320.person;
create table db_0320.tbl_person (
name string comment 'name',
age float comment 'age',
location string comment 'location',
friends array<string> comment 'friends',
score map<string, double> comment 'score',
address struct<number: tinyint, street: string, city: string>
)
row format delimited
fields terminated by '\001'
collection terminated by '\002'
map keys terminated by '\003'
lines terminated by '\n'
stored as textfile;
HiveQL 数据定义
概览
- HiveQL 和 MySQL 比较接近,但也有较大差异
- Hive 不支持行级插入、更新及删除操作
- Hive 不支持事务
- 大多数情况下 HiveQL 和其他 SQL 很像
- 查询、分组、过滤及连接
常见查询
-- 新建数据库
> create database db_test;
> create database if not exists db_test;
-- 查看所有的库
> show databases;
-- 使用正则表达式
-- 查询以 db_ 开头 的所有数据库
> show databases like 'db_*'
-- 查看库里的表
> show tables from db_test;
-- 删库(删库之前必须先删除库中的表,或者使用关键字 CASCADE)
> drop database if exists db_test cascade;
-- 查看表属性
> desc formatted tbl_test;
-- 如果只想查看某一列的信息,只需在表名后增加这一列的名称即可(亲测报错:missing EOF at '.' near 'tbl_person')
> describe db_0320.tbl_person.score;
-- 拷贝一张已存在的表
> create table if not exists tbl_test1 like tbl_test;
内部表与外部表(MANAGED_TABLE & EXTERNAL_TABLE)
使用 EXTERNAL 创建的表是外部表,否则就是内部表。内部表默认存储在 user/hive/warehouse/下, 当删除一个表时,Hive 会删除该目录下存储的数据;而删除外部表时,只会删除表的元数据,不会删除表数据。严格说,Hive 管理着这么目录和文件,但是不对其拥有完全控制权。
外部表示例:
1、先建立一个目录,存放外部表要操作的数据
> dfs -mkdir /hdp/0322
2、建表并指向外部表空间
drop table if exists db_0320.ex_tbl_student;
create external table if not exists db_0320.ex_tbl_student (
name string comment 'name',
age float comment 'age',
class string comment 'class'
)
row format
delimited fields terminated by ','
location '/hdp/0322/';
3、准备数据并上传至 HDFS
> dfs -put ~/Documents/ex_tbl_student.txt /hdp/0323/
文件内容:
zhangsan,12,一班
lisi,14,二班
wangwu,16,三班
4、将数据导入外部表中
> load data inpath '/hdp/0323/ex_tbl_student.txt' overwrite into table db_0320.ex_tbl_student;
5、确认数据及操作
分区表和管理表
分区将数据分散在多个目录下,可以提高查询性能。
如果表中数据或者分区中的数据量巨大,执行一个包含所有分区的查询会出发巨大的 MR 任务,可以将 hive.mapred.mode=strict
设置成严格模式禁止提交任务。
创建分区表:
drop table if exists db_0322.tbl_student;
create table if not exists db_0322.tbl_student (
name string comment 'name',
age float comment 'age',
class string comment 'class'
)
partitioned by (grade string comment 'grade');
查看分区:
> desc partitions db_0322.tbl_student;
导入数据至分区表:
> load data inpath 'tbl_student.txt' overwrite into table tbl_student partition (grade='grade2');
为外部分区表增加一个分区:
> alter table log add partition(year=2012, month=1, day=1);
对表的操作
删除表:
> drop table if exists db_0323.tbl_test;
可以了解下 Hive 的回收站功能。
修改表:可以使用 alter table 语句修改表,这种方式会修改表的元数据,不会修改数据本身。
-- 重命名表
> alter table tbl_test rename to tbl_test1;
-- 增加分区,给没有分区的表添加分区会报错
> alter table tbl_test add if not exists partition (city='Beijing');
-- 删除分区
> alter table tbl_test2 drop if exists partition (city = 'Beijing');
-- 修改字段
> alter table tbl_test2 change column name username string comment 'username' after column1;
-- 新增一个字段
> alter table tbl_test1 add columns (age float comment 'age');
-- 修改表属性
> alter table tbl_test1 set tblproperties ('note'='test note....')
-- 执行钩子,当往表中写入数据时触发执行
> alter table tbl_test touch partition(year=2021, month=12, day=1);
-- 将分区内的文件打包成 Hadoop 压缩包(HAR),使用 unarchive 反向操作
> alter table ... archive partition (year, month, day);
-- 防止分区被修改或删除(报错)
> alter table tbl_test partition (year=2021, month=10, day=1) enable no_drop;
HiveQL 数据操作
Hive 不支持行级数据插入、更新及删除,只能通过大批量的方式将数据导入表中。
> load data local inpath '${env:HOME}/data' overwrite into table tbl_test partition (year = 2022, month = 3, day = 22);
local 表示本地目录,如果不加 local 则表示 hdfs 上的文件。
Hive 不会校验导入的数据和表的模式是否匹配,但是会校验文件格式是否和表的定义一致。
通过查询向表中导入数据:
use db_0323;
from tbl_test3_tmp tmp
insert overwrite table tbl_test3
partition (city = 'Beijing')
select name where tmp.city = 'Beijing'
insert overwrite table tbl_test3
partition (city = 'Tianjin')
select name where tmp.city = 'Tianjin'
insert overwrite table tbl_test3
partition (city = 'Tianjing')
select name where tmp.city = 'Tianjing';
如果一个分区一个分区的查出来再导入的话,会非常繁琐,可以使用动态分区插入来避免这个问题。
use db_0323;
insert overwrite table tbl_test3
select name, city
from tbl_test3_tmp;
最后的几列顺序要和分区字段一致,Hive 根据列位置来确定分区字段,而不是名称。并且静态分区字段必须位于动态分区字段之前。
dfs -ls /user/hive/warehouse/db_0323.db/tbl_test3
查看分区:
Found 3 items
drwxr-xr-x - longkun supergroup 0 2022-03-24 23:56 /user/hive/warehouse/db_0323.db/tbl_test3/city=Beijing
drwxr-xr-x - longkun supergroup 0 2022-03-24 23:56 /user/hive/warehouse/db_0323.db/tbl_test3/city=Tianjin
drwxr-xr-x - longkun supergroup 0 2022-03-24 23:56 /user/hive/warehouse/db_0323.db/tbl_test3/city=Tianjing
动态分区功能默认是关闭的。开启后,默认以“严格”模式执行,这种模式下,要求至少有一列字段是静态分区,有助于防止因设计错误导致产生大量的分区。
动态分区相关属性:
属性名称 | 缺省值 | 描述 |
---|---|---|
hive.exec.dynamic.partition | false | 设置成 true,开启动态分区功能 |
hive.exec.dynamic.partition.mode | strict | 设置成 no strict,允许所有列都是动态分区 |
hive.exec.max.dynamic.partitions.pernode | 100 | 每个 mapper 和 reducer 可以创建的最大分数,超过会报错 |
hive.exec.max.dynamic.partitions | 1000 | 一个动态分区语句可以创建的最大动态分区个数,超过会报错 |
hive.exec.max.created.files | 100000 | 全局可以创建的最大文件个数,超过会报错 |
单个查询语句创建表并加载数据:
create table tbl_test4 as
select name
from tbl_test3
where city = 'Beijing';
导出数据 insert directory
:
use db_0323;
-- 第一种方式
insert overwrite local directory '${env:HOME}/Documents/Hive/export'
select name, city
from tbl_test3
where city = 'Beijing';
-- 第二种方式
from tbl_test3 tmp
insert overwrite local directory '${env:HOME}/Documents/Hive/export-beijing'
select name where tmp.city = 'Beijing'
insert overwrite local directory '${env:HOME}/Documents/Hive/export-tianjin'
select name where tmp.city = 'Tianjin'
insert overwrite local directory '${env:HOME}/Documents/Hive/export-tianjing'
select name where tmp.city = 'Tianjing';
Hive 中没有临时表的概念。
HiveQL 查询
常用函数:
返回值类型 | 函数 | 描述 |
---|---|---|
BIGINT | round(double d) | 取近似值 |
DOUBLE | round(double d, int n) | 取近似值,保留 n 位小数 |
BIGINT | floot(double d) | 向下取整 |
BIGINT | ceil(double d) | 向上取整 |
DOUBLE | rand() | 生成一个 DOUBLE 类型的随机数 |
STRING | concat_ws(string separator, string s1, string s2…) | 使用指定的分隔符连接字符串 |
STRING | substr(string s, int start, int length) | 截取子字符串 |
STRING | to_date(string date) | ‘2022-01-01 10:20:12’ -> ‘2022-01-01’ |
INT | year(string date) | 返回年 |
INT | month | 获取月份 |
INT | date_diff(string date1, string date2) | 获取两个日期相差天数 |
INT | date_add(string date, int days) | 日期相加 |
INT | date_sub(string date, int days) | 日期相减 |
嵌套 SELECT
from (
select name, age
from tbl_test3
where age > 10
) tmp
select tmp.*
where tmp.name like 'zhang%';
CASE WHEN
select name,
case
when age < 18 then '未成年'
when age >= 18 and age < 60 then '成年'
else '老年'
end as age,
sex
from tbl_test;
避免进行 MapReduce
- where 条件中过滤字段是分区字段
- 没有 where 条件的 select 语句
- hive.exec.mode.local.auto=true 会尝试本地模式执行其他 SQL
类型转换 cast
最好使用 ceil / floor / round 等函数来将字符串转为整数。
抽样查询
按照(基于行数的)百分比进行抽样。
select * from tbl_student_info_tmp tablesample(50 percent);
UNION ALL
将多个子表进行合并,这几个子表的列及顺序及类型必须完全一致,理论上可以改为多个 where 语句。
HiveQL 视图
可以使用视图简化查询:
-- 所有来自北京的学生
create view view_student_beijing as
select uid, name, age, grade, class
from tbl_student_info
where home_address.province = '北京';
-- 来自北京年龄小于 20 的学生
select *
from view_student_beijing
where ceil(age) <= 20;
删除视图:
drop view if exists view_student_beijing;
视图不能做为 load 和 insert 的目标表。视图是只读的,只允许改变与数据信息 tblpropreties。
alter view set tblproperties('created_by'='system');
HiveQL 索引
模式设计
分区表
随着系统运行时间的增加,表数据量会越来越大,Hive 查询通常是全表扫描,性能会越来越低。可以使用分区表提高性能。
create table tbl_test(name string)
partitioned by (kind string);
分区列只是一个目录名称,实际不存储这一列数据。
应该选择合适的分区字段,如果分区数太大,会创建大量的 Hadoop 文件及文件夹,反而会降低查询效率。
可以选择多个分区字段来进行分区。
create table student (
name string,
sex string
) partitioned by (grade string, class string);
查看分区:
show partitions table_name;
唯一键和标准化
Hive 没有关系型数据库中的唯一键和序列自增,应避免对非标准化(?)数据进行 JOIN 操作,复杂的数据类型,可以通过 Array、Map、STRUCT 实现。
同一份数据处理多次
Hive 可以从一个数据源产生多个数据聚合,而无需每次聚合都重新扫描一次,可以节省很多时间。
from tbl_student_info_tmp
insert overwrite tbl_student_info1 where age > 10;
insert overwrite tbl_student_info2 where age > 20;
对于每个表的分区
对于一些中间数据可以使用分区,可以保证任务重跑的时候不会覆盖所有的数据,只对目标数据进行处理。
这几个月负责公司一些数据的处理,基本都是按月拉结果,使用月末的时间做为分区,这样每一个月的数据都可以留存下来成为历史数据,不受下个月数据的影响。
分桶 🪣
Hive表分区的实质是分目录(将超大表的数据按指定标准细分到指定目录),且分区的字段不属于Hive表中存在的字段;分桶的实质是分文件(将超大文件的数据按指定标准细分到分桶文件),且分桶的字段必须在Hive表中存在。
分桶的好处在于表中的数据已经按条件分到了多个文件中,join 或者其他计算时只需取符合条件的数据进行处理,从而提高性能。
-- 创建分桶表
use db_0327;
drop table if exists bucket_tbl_student_info;
create table if not exists bucket_tbl_student_info (
uid string comment 'uid',
name string comment 'name',
age int comment 'age'
) clustered by (age) into 2 buckets
row format delimited
fields terminated by ','
lines terminated by '\n';
-- 将数据写入分桶表
set hiveconf:hive.enforce.bucketing=true;
use db_0327;
from tbl_student_info_tmp
insert overwrite table bucket_tbl_student_info
select uid, name, floor(age) as age where 1 = 1;
-- 如果不设置 hiveconf:mapred.reduce.tasks,则需要手动设置与分桶个数相等的 reducer 数
set hiveconf:mapred.reduce.tasks=2;
use db_0327;
from tbl_student_info_tmp
insert into table bucket_tbl_student_info
select uid, name, floor(age)
where 1 = 1
cluster by age;
-- 从分桶表中获取抽样数据
select uid, name, age from bucket_tbl_student_info tablesample(bucket 1 out of 2 on age);
将 hive.enforce.bucketing 设置成 true 之后,Hive 会在目标表初始化过程中设置一个正确的 reducer 数。
为表新增列
Hive 表对数据格式的要求比较宽松,列的信息在元数据中,新增列或者删除列只是改变元数据。如果列的个数比实际数据的列要多,则多余的列会被省略,相反,则会以 NULL 填充。
Hive 表新增列:
alter table tbl_access_log add columns (rank1 int, rank2 int);
在新增列之前入库的数据,查询的时候新加的字段会用 NULL 填充。
使用列存储表 📦
Hive 默认使用行式存储。假设有足够多的列,列中有很多的重复数据,这种类型的数据使用列式存储性能会更好,查询的时候不要加载所有列的数据。
参见 15.3.2 RCfile 使用这种格式?
使用压缩 🗜️
几乎所有的情况下,使用压缩都能降低磁盘占用量,降低 I/O 以提高查询速度。
使用外部数据或者非压缩格式时无法使用压缩。
压缩和解压缩都会消耗 CPU 资源,但是大多数 MR 任务都是 I/O 密集型任务,所以 CPU 开销通常不是问题。
Hive 常见问题及解决方案记录 📝
1、启动 Hive 报错:Cannot create directory /tmp/hive/longkun/50be98c2-62e0-4b37-9002-c2270fed6a20. Name node is in safe mode.
控制台日志提示无法创建临时目录,Hive 处于安全模式中。
安全模式主要是 HDFS 系统的时候检查 DataNode 上数据块的有效性,同时根据策略复制和删除部分数据块,运行的时候也可以通过命令进入安全模式。安全模式中不允许修改和删除数据。
可以通过命令来离开安全🔐模式:
hadoop dfsadmin -safemode leave
离开安全模式之后,Hive 正常启动。