【大数据Hive】hive 表设计常用优化策略

目录

一、前言

二、hive 普通表查询原理

2.1 操作演示说明

2.1.1 创建一张表,并加载数据

2.1.2 统计3月24号的登录人数

2.1.3 查询原理过程总结

2.2 普通表结构带来的问题

三、hive分区表设计

3.1 区表结构 - 分区设计思想

3.2 操作演示

3.2.1 创建分区表 按照登录日期分区

3.2.2 开启动态分区

按登录日期分区

基于分区表查询数据

查询先检索元数据

查询执行计划

四、hive分桶表设计

4.1 Hive中Join的问题

4.2 分桶表设计思想

4.3 创建分桶表操作

创建第一张普通表

构建分桶emp表

创建第二张普通表dept并加载数据

构建分桶dept表并加载数据

4.4 普通表与分桶表join执行分析

普通表的join执行计划分析

分桶的Join执行计划分析

 五、hive索引设计

5.1 hive索引说明

5.2 Hive中索引基本原理

5.2.1 Hive索引目的

5.3 索引的使用

5.4 Hive索引的问题

六、写在文末


一、前言

不管是关系性数据库,比如像mysql,还是类关系型数据库,像mongodb,为了确保在建表开始使用之后,能够充分发挥数据表的高性能查询,需要在表的设计阶段,从表的设计,索引的设计,分区的设计等等一系列因素综合去平衡和考虑,以免为上线后的优化工作带来麻烦。本篇将介绍hive关于表设计常用的一些优化策略。

二、hive 普通表查询原理

通过之前的学习,想必大家对hive的查询原理不再陌生,下图是hive查询的原理图;

为什么要说查询原理呢,理解一个软件的设计有必要对其原理做一定的了解,就像之前学习mysql一样,只有了解了innodb引擎的工作原理,才能更好的指导我们sql的做性能优化,关于hive的查询原理,再做如下补充:

  • Hive的设计思想是通过元数据解析描述将HDFS上的文件映射成表;
  • 基本的查询原理是当用户通过HQL语句对Hive中的表进行复杂数据处理和计算时,默认将其转换为分布式计算MapReduce程序对HDFS中的数据进行读取处理的过程;

hive自身不存储数据,其数据依赖的载体为hdfs,比如当我们创建一个数据库,一张表之后,在hdfs文件目录上就出现了一个目录;

 在表下面加载数据之后,表的文件目录下,可以继续看到一个数据文件;

2.1 操作演示说明

2.1.1 创建一张表,并加载数据

create table tb_login(
                         userid string,
                         logindate string
) row format delimited fields terminated by '\t';


load data local inpath '/usr/local/soft/hivedata/login.log' into table tb_login;

select * from tb_login;

检查数据是否加载成功

 检查hdfs数据目录,可以看到表数据已经加载到目录下

2.1.2 统计3月24号的登录人数

select
    logindate,
    count(*) as cnt
from tb_login
where logindate = '2021-03-24'
group by logindate;

通过sql的执行过程,可以看到底层是走了MR的过程; 

 如果使用explain来分析一下执行的过程

explain extended
select
    logindate,
    count(*) as cnt
from tb_login
where logindate = '2021-03-24'
group by logindate;

重点关注下面的那一段关于数据扫描的信息,这段信息要表达的意思是,执行上面的sql时,需要对表的数据目录下的文件数据进行全表扫描,当目录下的数据量非常大的时候,全表扫描将是非常耗时和耗费性能的;

2.1.3 查询原理过程总结

通过上面的过程分析,关于hive普通表的查询过程原理做简单的小结

1)当执行查询计划时,Hive会使用表的最后一级目录作为底层处理数据的输入

Step1:先根据表名在元数据中进行查询表对应的HDFS目录

Step2: 然后在hive的数据库下找到下面这张表,定位到表的数据目录在hdfs上面的具体路径;

2) 然后将整个HDFS中表的目录作为底层查询的输入,可以通过explain命令查看执行计划依赖的数据

2.2 普通表结构带来的问题

通过上面的操作演示,有心的小伙伴们可能发现了一些问题,更进一步,我们来看下面的这个场景:

1、假设每天有1G的数据增量,一年就是365GB的数据,按照业务需求,每次只需要对其中一天的数据进行处理,也就是处理1GB的数据;

2、程序会先加载365GB的数据,然后将364GB的数据过滤掉,只保留一天的数据再进行计算,导致了大量的磁盘和网络的IO的损耗;

三、hive分区表设计

在之前的讲解中,我们使用过hive的分区表,接下来再从原理层面再次聊聊hive分区表的设计与思想。

3.1 区表结构 - 分区设计思想

Hive提供了一种特殊的表结构来解决——分区表结构,分区表结构的设计思想是:

  • 据查询的需求,将数据按照查询的条件【一般以时间】进行划分分区存储;
  • 将不同分区的数据单独使用一个HDFS目录来进行存储;
  • 当底层实现计算时,根据查询的条件,只读取对应分区的数据作为输入,减少不必要的数据加载,提高程序的性能;

3.2 操作演示

在上面的案例中,按照登陆日期进行分区存储到Hive表中,每一天一个分区,在HDFS的底层就可以自动实现将每天的数据存储在不同的目录中;

接下来看具体的操作过程

3.2.1 创建分区表 按照登录日期分区

create table tb_login_part(
    userid string
)
    partitioned by (logindate string)
    row format delimited fields terminated by '\t';

执行过程

3.2.2 开启动态分区

set hive.exec.dynamic.partition.mode=nonstrict;

按登录日期分区

insert into table tb_login_part partition(logindate)
select * from tb_login;

执行过程

执行完成后再次检查hdfs表的数据目录,可以看到就按照日期创建了3个分区目录;

基于分区表查询数据

select
    logindate,
    count(*) as cnt
from tb_login_part
where logindate = '2021-03-23' or logindate = '2021-03-24'
group by logindate;

可以发现在分区表的情况下查询速度明显提升了; 

从之前对hive分区表的学习我们也了解到,使用分区表的目的就是为了减少数据文件的扫描,从而达到提升查询性能的目的,下面来看看具体的原理,

查询先检索元数据

元数据中记录该表为分区表,即PARTITIONS这张表中,并且查询过滤条件为分区字段,所以找到该分区对应的HDFS目录;

 然后再去SDS表中可以看到分区表在hdfs存储的具体目录地址;

查询执行计划

如果此时再看执行计划,会有什么结果呢?

explain extended
select
    logindate,
    count(*) as cnt
from tb_login_part
where logindate = '2021-03-23' or logindate = '2021-03-24'
group by logindate;

此时不难看出,基于分区表的情况下,不再是做全表扫描了,而是针对各自的分区做数据的扫描;

四、hive分桶表设计

4.1 Hive中Join的问题

默认情况下,Hive底层是通过MapReduce来实现的,MapReduce在处理数据之间join的时候有两种方式:MapJoin、ReduceJoin,其中MapJoin效率较高,如果有两张非常大的表要进行Join,底层无法使用MapJoin提高Join的性能,只能走默认的ReduceJoin,而ReduceJoin必须经过Shuffle过程,相对性能比较差,而且容易产生数据倾斜;

基于上面的问题,可以考虑使用hive的分桶表来设计和优化;

4.2 分桶表设计思想

分区表是将数据划分不同的目录进行存储,而分桶表是将数据划分不同的文件进行存储

分桶表的设计是按照一定的规则【底层通过MapReduce中的多个Reduce来实现】将数据划分到不同的文件中进行存储,构建分桶表。

 有了分桶表之后,如果再次对两张比较大的数据表进行join的时候,由于两张表按照相同的划分规则【比如按照Join的关联字段】将各自的数据进行划分(即基于分桶表的设计规则之下),在Join时,就可以实现Bucket与Bucket的Join,避免不必要的比较,减少笛卡尔积数量;

4.3 创建分桶表操作

创建第一张普通表

--创建普通表
create table tb_emp01(
                         empno string,
                         ename string,
                         job string,
                         managerid string,
                         hiredate string,
                         salary double,
                         jiangjin double,
                         deptno string
) row format delimited fields terminated by '\t';

--加载数据
load data local inpath '/usr/local/soft/data/emp01.txt' into table tb_emp01;

select * from tb_emp01;

执行完成后检查数据是否加载成功;

构建分桶emp表

create table tb_emp02(
                         empno string,
                         ename string,
                         job string,
                         managerid string,
                         hiredate string,
                         salary double,
                         jiangjin double,
                         deptno string
)
    clustered by(deptno) sorted by (deptno asc) into 3 buckets
    row format delimited fields terminated by '\t';

执行建表sql

将数据写入分桶表

insert overwrite table tb_emp02
select * from tb_emp01;

由于表的数据量较大,执行耗时较长,执行完成后,可以检查数据是否加载成功

 从hdfs文件目录上也可以看出来,数据被分散存储到各个虚拟的“桶”中;

创建第二张普通表dept并加载数据

--	构建普通dept表
create table tb_dept01(
                          deptno string,
                          dname string,
                          loc string
)
    row format delimited fields terminated by ',';

-- 加载数据
load data local inpath '/usr/local/soft/data/dept01.txt' into table tb_dept01;

select * from tb_dept01;

执行过程

构建分桶dept表并加载数据

-- 构建分桶dept表
create table tb_dept02(
                          deptno string,
                          dname string,
                          loc string
)
    clustered by(deptno) sorted by (deptno asc) into 3 buckets
    row format delimited fields terminated by ',';

-- 数据写入分桶表
insert overwrite table tb_dept02
select * from tb_dept01;

执行过程

 从hdfs目录上面可以看到tb_emp02表的数据已经分好了桶;

4.4 普通表与分桶表join执行分析

上面创建了2张普通表以及两张分桶表,基于以上的数据,我们使用explain分别执行一下看看执行计划如何;

普通表的join执行计划分析

explain
select
    a.empno,
    a.ename,
    a.salary,
    b.deptno,
    b.dname
from tb_emp01 a join tb_dept01 b on a.deptno = b.deptno;

执行上面的explain计划分析,从显示结果来看,就是单纯的两张表的inner join操作,也就是两张表进行笛卡尔的乘积;

分桶的Join执行计划分析

--开启分桶SMB(Sort-Merge-Buket) join
set hive.optimize.bucketmapjoin = true;
set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin.sortedmerge = true;

--查看执行计划
explain
select
    a.empno,
    a.ename,
    a.salary,
    b.deptno,
    b.dname
from tb_emp02 a join tb_dept02 b on a.deptno = b.deptno;

执行上面的sql之后,再次来看看分析的结果如下,此时可以看到,这时尽管也存在表的join,却是bucket桶与桶之间的数据的join,由于bucket中的数据量比原始数据要小很多,笛卡尔的乘积结果也会小很多,这样就提升了整体的关联查询的效率;

 五、hive索引设计

使用过mysql的同学对索引应该不陌生,索引可以说是用于优化mysql表查询性能的利器,在hive中也提供了索引的功能,用于提升数据查询时的性能。

5.1 hive索引说明

Hive中提供了索引的设计,允许用户为字段构建索引,提高数据的查询效率。但是Hive的索引与关系型数据库中的索引并不相同,比如,Hive不支持主键或者外键索引。

Hive索引可以建立在表中的某些列上,以提升一些操作的效率。

5.2 Hive中索引基本原理

当为某张表的某个字段创建索引时,Hive中会自动创建一张索引表,该表记录了该字段的每个值与数据实际物理位置之间的关系,例如数据所在的HDFS文件地址,以及所在文件中偏移量offset等信息。

5.2.1 Hive索引目的

提高Hive表指定列的查询速度。没有索引时,类似WHERE tab1.col1 = 10的查询,Hive会加载整张表或分区,然后处理所有的行,但是如果在字段col1上面存在索引时,那么只会加载和处理文件的一部分。

5.3 索引的使用

创建索引语句

-- 为表中的userid构建索引
create index idx_user_id_login on table tb_login_part(userid)
-- 索引类型为Compact,Hive支持Compact和Bitmap类型,存储的索引内容不同
as 'COMPACT'
-- 延迟构建索引
with deferred rebuild;

索引创建完成后,还需要运行一个MR任务来构建索引,相当于是为索引在hdfs目录中创建一个数据目录;

alter index idx_user_id_login ON tb_login_part rebuild;

查看索引结构

desc default__tb_login_part_idx_user_id_login__;

查看索引内容

select * from default__tb_login_part_idx_user_id_login__;

删除索引

DROP INDEX idx_user_id_login ON tb_login_part;

5.4 Hive索引的问题

由于hive索引自身的机制在实际使用中并不推荐,在3.0之后的某个版本直接被移除了,其主要问题如下:

  • Hive构建索引的过程是通过一个MapReduce程序来实现的;
  • 每次Hive中原始数据表的数据发生更新时,索引表不会自动更新;
  • 必须手动执行一个Alter index命令来实现通过MapReduce更新索引表,导致整体性能较差,维护相对繁琐;

六、写在文末

在大数据场景下,表的优化是一个永恒的话题,在实际生产过程中,在表的优化思路上通常是通过多种策略组合的方式寻求最优解,前提是需要对常用的优化策略有深入的了解才能合理的使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/387078.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

每日一题(数字颠倒,单词倒排)

数字颠倒_牛客题霸_牛客网 (nowcoder.com) #include <stdio.h>int main() {char arr[100];gets(arr);int lenstrlen(arr);for(int ilen-1;i>0;i--){printf("%c",arr[i]);}return 0; } 单词倒排_牛客题霸_牛客网 (nowcoder.com) #include <stdio.h> #…

《Java 简易速速上手小册》第4章:Java 中的异常处理(2024 最新版)

文章目录 4.1 异常类型和错误 - 遇见你的小怪兽4.1.1 基础知识4.1.2 重点案例&#xff1a;文件读取处理4.1.3 拓展案例 1&#xff1a;处理空指针异常4.1.4 拓展案例 2&#xff1a;捕获多个异常 4.2 异常处理机制 - 穿上你的超级英雄斗篷4.2.1 基础知识4.2.2 重点案例&#xff1…

Vuex 模块的详解

Vuex 模块是将 store 分割成多个模块的一种方式&#xff0c;每个模块都有自己的状态、mutations、actions 和 getters。这有助于更好地组织和管理应用程序的状态。 创建模块&#xff1a; 首先&#xff0c;需要创建一个模块。可以在 store 中定义一个新的模块对象&#xff0c…

python小项目----多重剪切板

代码&#xff1a; import shelve,pyperclip,sysimport mcbmcbShelfshelve.open(mcb)# 保存剪切板内容 if len(sys.argv)3 and sys.argv[1].lower()save:#剪切板的内容保存到第三个参数中mcbShelf[sys.argv[2]]pyperclip.paste()print("你的剪切板中的内容将被保存到mcbSh…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 2月14日,星期三

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年2月14日 星期三 农历正月初五 1、 第十四届全国冬季运动会将于17日开幕&#xff0c;部分赛事今天起陆续开赛。 2、 2024年购房政策将进一步宽松&#xff0c;专家称今年买房性价比更高。 3、 春节档票房突破45亿元&#…

算法学习——LeetCode力扣回溯篇2

算法学习——LeetCode力扣回溯篇2 40. 组合总和 II 40. 组合总和 II - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字…

(二)【Jmeter】专栏实战项目靶场drupal部署

该专栏后续实战示例&#xff0c;都以该篇部署的项目展开操作。 前置条件 参考“&#xff08;一&#xff09;【Jmeter】JDK及Jmeter的安装部署及简单配置” 安装部署Jmeter&#xff0c;从文章最后下载“Postman、Rancher.ova、VirtualBox-7.0.12-159484-Win.exe、Xshell-7.0.01…

CMU和ETH联合研发了一个名为 「敏捷但安全」的新框架,为四足机器人在复杂环境中实现高速运动提供了解决方案

在高速机器人运动领域&#xff0c;实现同时兼顾速度和安全一直是一大挑战。但现在&#xff0c;卡内基梅隆大学&#xff08;CMU&#xff09;和苏黎世联邦理工学院&#xff08;ETH&#xff09;的研究团队带来了突破性进展。他们开发的新型四足机器人算法&#xff0c;不仅能在复杂…

Leetcode 452. 用最少数量的箭引爆气球435. 无重叠区间

class Solution {public int findMinArrowShots(int[][] points) {Arrays.sort(points,(o1,o2)->Integer.compare(o1[0], o2[0]));int count1;//箭的数量for(int i1;i<points.length;i) {if(points[i][0]>points[i-1][1]) {count;//边界没重合&#xff0c;又需要一支箭…

如何重新安装 macOS

你可以使用电脑的内建恢复系统“macOS 恢复”来重新安装 Mac 操作系统。不但简单快捷&#xff0c;而且重新安装后不会移除你的个人数据。 将 Mac 关机 选取苹果菜单  >“关机”&#xff0c;然后等待 Mac 关机。如果你无法将 Mac 关机&#xff0c;请按住它的电源按钮最长 …

第六篇:MySQL图形化管理工具

经过前五篇的学习&#xff0c;对于数据库这门技术的理解&#xff0c;我们已经在心中建立了一个城堡大致的雏形&#xff0c;通过命令行窗口&#xff08;cmd&#xff09;快速上手了【SQL语法-DDL-数据定义语言】等相关命令 道阻且长&#xff0c;数据库技术这一宝藏中还有数不清的…

猫头虎分享: 探索软件系统架构的革新之路

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

Swift Combine 网络受限时从备用 URL 请求数据 从入门到精通十四

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

python 基础知识点(蓝桥杯python科目个人复习计划40)

今日复习内容&#xff1a;矩阵乘法&#xff0c;高斯消元 哈哈&#xff0c;我来干回老本行&#xff0c;复习点儿数学类专业学的东西 因为电脑上制作费时间&#xff0c;所以我直接用我的《高等代数》和《数值分析》笔记。 一.矩阵乘法 例题1&#xff1a;矩阵相乘 题目描述&am…

three.js 细一万倍教程 从入门到精通(三)

目录 五、详解PBR材质纹理 5.1、详解PBR物理渲染 5.2、标准网格材质与光照物理效果 5.3、置换贴图与顶点细分设置 5.4、设置粗糙度与粗糙度贴图 5.5、设置金属度与金属贴图 5.6、法线贴图应用 5.7、如何获取各种类型纹理贴图 5.8、纹理加载进度情况 单张图片加载 多…

Java学习手册——第七篇基础语法

Java学习手册——第七篇基础语法 1. 注释2. 顺序语句3. 条件语句3.1 if语句3.2 switch语句 4. 循环语句4.1 for循环4.2 while 语句4.3 do...while语句 本篇为大家快速入门Java基础语法&#xff0c;了解一个语言的基础语法是必要的&#xff0c; 因为我们后期都是需要用这些基础语…

基于CU,PO,RD,IPO矩阵图分析数据资产-自创

术语 数据资产&#xff1a;数据资产是具有价值的数据资源。没有价值的数据资源&#xff0c;通过采集&#xff0c;整理&#xff0c;汇总等加工后&#xff0c;也可以成为具有直接或间接价值的数据资产。传统企业逐渐数字化转型&#xff0c;尤其是互联网企业&#xff0c;都十分重视…

文献速递:肿瘤分割---- 弱监督肝肿瘤分割,使用Couinaud区段标注

文献速递&#xff1a;肿瘤分割---- 弱监督肝肿瘤分割&#xff0c;使用Couinaud区段标注 01 文献速递介绍 肝癌是世界上导致癌症死亡的主要原因之一&#xff0c;也是第二大常见的癌症死因。本稿件于2021年10月28日收到&#xff0c;2021年11月24日修订&#xff0c;2021年12月1…

[Linux开发工具]项目自动化构建工具-make/Makefile

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.背景2.依赖关系和依…

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏17(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言制作木板UI直接复制和工具一样的即可检查背包是否有指定数量的空插槽 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇…