传统数仓无法满足快速增长的海量数据存储需求,无法有效处理不同类型的数据,并且计算和处理能力不足,因此就诞生了HDFS(Hadoop Distributed File System),但是HDFS的使用门槛不够友好,大家熟悉的SQL不能直接跑,因此需要一个框架,使用SQL来做HDFS的查询。Hive正是基于类似SQL的语言完成对hdfs数据的查询分析的框架。
一、Hive的特点
- Hive可以查询和管理PB级别的分布式数据
- 本身不存储和处理数据,可以看成是一种工具
- 依赖HDFS存储数据
- 依赖MapReduce(默认)、Tez、Spark等计算引擎
- HiveQL支持类似普通SQL的查询语言
- 支持原始类型包括数值型、Boolean,字符串,时间戳,复杂类型包括数组,map,struct
二、Hive同传统数据库的区别
Hive | 传统数据库 | |
---|---|---|
设计目的 |
Hive是为数据仓库设计的,主要用于海量数据的存储和分析 | 传统数据库主要用于业务平台的事务处理,支持高频的数据增删改查操作,通常用于在线应用 |
数据存储位置 |
存储在HDFS中,依赖于HDFS进行分布式文件存储 | 将数据保存在块设备或本地文件系统中 |
数据更新能力 |
不支持对数据的改写和添加,所有的数据都是在加载时确定好的 | 通常需要经常进行数据修改,可以使用INSERT INTO…VALUES添加数据,使用UPDATE…SET修改数据 |
适用场景 |
适用于需要进行大规模数据分析的场景,如数据挖掘和报表生成 |
三、Hive 架构和组件
- Metastore是一个中央存储库,存储关于表和分区结构的元数据信息,包括列和列类型信息
- Metastore通常是一个关系数据库。Hive的元数据可能要面临不断地更新/修改和读取操作,所以它显然不适合使用Hadoop文件系统进行存储,目前Hive将元数据存储在RDBMS中,比如存储在MySQL。 对外提供了一个Thrift接口,用于查询和操作Hive元数据。
四、分区 & 分桶
一句话,分区分桶是为了提高Hive的查询效率。
4.1 分区
基于分区键把具有相同分区键的数据存储在一个目录下,在查询某一个分区的数据的时候,只需要查询相对应目录下的数据,而不会执行全表扫描。
如上图所示,假如你有一个存储学生信息的表,表名为 student_details,列分别是 student_id,name,department,year 等。现在,如果你想基于 department 列对数据进行分区。那么属于同一个 department 的学生将会被分在同一个分区里面。
在物理上,一个分区其实就是表目录下的一个子目录。
假如在 student_details 表里面有三个 department 的数据,分别为 EEE,ECE 和 ME。那么这个表总共就会有三个分区,也就是图中的绿色方块部分。对于每个 department ,您将拥有与该 department 相关的所有数据,这些数据位于表目录下的单独子目录中。
如果 department = EEE 的学生数据被存储在/user/hive/warehouse/student_details/department=EEE 目录下。那么查询 department 为 EEE 的学生信息,只需要查询 EEE 目录下的数据即可,不需要全表扫描,这样查询的效率就比较高。而在真实生产环境中,你需要处理的数据可能会有几百 TB,如果不分区,在你只需要表的其中一小部分数据的时候,你不得不走全表扫描,这样的查询将会非常慢而且浪费资源。
Hive动态分区与静态分区的区别及使用场景
静态分区:在插入数据时,用户手动指定分区的值
动态分区:在插入数据时,分区的值由数据本身决定,用户不需要手动指定
在静态分区中,用户在插入数据时,需要明确指定分区的值。这意味着每个插入操作都需要提供一个具体的分区路径。例如,当将数据插入到某个按“日期”分区的表中时,用户需要明确指定“日期”的值。假设我们有一个销售记录表,按“日期”进行静态分区。插入数据的SQL语句如下:
INSERT INTO sales PARTITION (date='2023-10-01')
SELECT * FROM temp_sales WHERE sale_date = '2023-10-01';
在动态分区中,用户在插入数据时,不需要手动指定分区的值。Hive会根据插入数据中的某一列的值自动创建对应的分区。用户只需在INSERT语句中指定分区列,而不必指定具体的值:
INSERT INTO sales PARTITION (date)
SELECT sale_id, product_id, amount, sale_date FROM temp_sales;
静态分区的使用场景
- 数据量小且变化不频繁
- 分区数量已知且稳定
- 开发和测试环境
动态分区的使用场景
- 数据量大且频繁变化(如在线交易系统,数据量大且每天的数据插入量不确定)
- 复杂的分区需求
- 实时数据处理
4.2 分桶
Hive 可以对每一个表或者是分区,进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive 是针对表的某一列进行分桶。Hive 采用对列值进行哈希计算,然后除以桶的个数求余的方式决定该条记录存放在哪个桶中。分桶的好处是可以获得更高的查询处理效率。使取样更高效。
每个桶只是表目录或者分区目录下的一个文件,如果表不是分区表,那么桶文件会存储在表目录下,如果表是分区表,那么桶文件会存储在分区目录下。所以你可以选择把分区分成 n 个桶,那么每个分区目录下就会有 n 个文件。
创建分区表语法:
CREATE TABLE table_name (column1 data_type, column2 data_type)
PARTITIONED BY (partition1 data_type, partition2 data_type,….);
分桶表创建命令:
CREATE TABLE table_name
PARTITIONED BY (partition1 data_type, partition2 data_type,….)
CLUSTERED BY (column_name1, column_name2, …)
SORTED BY (column_name [ASC|DESC], …)]
INTO num_buckets BUCKETS;
五、Hive 文件格式与压缩格式
存储格式行存储和列存储
- 行存储可以理解为一条记录存储一行,通过条件能够查询一整行数据。
- 列存储,以字段聚集存储,可以理解为相同的字段存储在一起。
5.1 存储格式
存储格式即是指表的数据是如何在HDFS上组织排列的。Hive中常用的存储格式有TEXTFILE 、SEQUENCEFILE、AVRO、RCFILE、ORCFILE、PARQUET等。主要在加载速度、压缩率、查询速度、存储方式等方面有一些差异。
TEXTFILE
- 数据表的默认格式,存储方式:行存储。
- 加载速度最快
- 可以使用Gzip压缩算法,但压缩后的文件不支持split(可能造成Map端的数据倾斜)。
- 在反序列化过程中,必须逐个字符判断是不是分隔符和行结束符,因此反序列化开销会比SequenceFile高几十倍。
SEQUENCEFILE