马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1、开启当地模式
大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理处罚大数据集的。不过,偶然Hive的输入数据量黑白常小的。在这种情况下,为查询触发执行使命消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过当地模式在单台呆板上处理处罚全部的使命。对于小数据集,执行时间可以显着被缩短。用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在得当的时间自动启动这个优化。
- set hive.exec.mode.local.auto=true;
- //开启本地mr
- //设置local mr的最大输入数据量,当输入数据量小于这个值时采用local mr的方式,默认为134217728,即128M
- set hive.exec.mode.local.auto.inputbytes.max=50000000;
- //设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
- set hive.exec.mode.local.auto.input.files.max=10;
复制代码 2、explain分析SQL语句
explain:只有对hql语句的表明。(Hive SQL)
Explain extended:对hql语句的表明,以及抽象表达式树的生成
- explain select * from emp;
- explain extended select * from emp;
复制代码- explain select deptno, avg(salary) avg_sal from emp group by deptno;
复制代码- 打印结果如下:
- STAGE DEPENDENCIES:
- -- 此处表示这个sql分为两步执行,第一步Stage-1 ,第二步Stage-0,Stage-0依赖于Stage-1
- Stage-1 is a root stage
- Stage-0 depends on stages: Stage-1
- STAGE PLANS:
- -- 执行第一步
- Stage: Stage-1
- Map Reduce -- 执行了MR任务
- Map Operator Tree:-- Map阶段执行的任务树
- TableScan -- 扫描表
- alias: emp
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- Select Operator -- 查询两个字段salary 和 deptno
- expressions: salary (type: int), deptno (type: int)
- outputColumnNames: salary, deptno
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- -- 分组操作
- Group By Operator
- -- 聚合操作 算出总的薪水和薪水的总个数
- aggregations: sum(salary), count(salary)
- keys: deptno (type: int)
- mode: hash
- outputColumnNames: _col0, _col1, _col2
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- Reduce Output Operator -- 输出操作
- key expressions: _col0 (type: int)
- sort order: +
- Map-reduce partition columns: _col0 (type: int)
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- value expressions: _col1 (type: bigint), _col2 (type: bigint)
- Execution mode: vectorized
- Reduce Operator Tree: -- Reduce操作的树
- Group By Operator
- aggregations: sum(VALUE._col0), count(VALUE._col1)
- keys: KEY._col0 (type: int)
- mode: mergepartial
- outputColumnNames: _col0, _col1, _col2
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- Select Operator
- expressions: _col0 (type: int), (_col1 / _col2) (type: double)
- outputColumnNames: _col0, _col1
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- File Output Operator
- compressed: false
- Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE
- table:
- input format: org.apache.hadoop.mapred.SequenceFileInputFormat
- output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
- serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
- Stage: Stage-0 -- 执行Stage-0
- Fetch Operator --执行抓取操作
- limit: -1 --没有什么限制
- Processor Tree:
- ListSink
- Time taken: 0.79 seconds, Fetched: 53 row(s)
复制代码 1)stage 相当于一个job,一个stage可以是limit、也可以是一个子查询、也可以是group by等。
2)hive默认一次只执行一个stage,但是如果stage之间没有相互依赖,将可以并行执行。
3)使命越复杂,hql代码越复杂,stage越多,运行的时间一样平常越长。
我们可以通过explain关键字来分析一个语句,但作为一个初学者只需要知道可以通过explain分析即可,没有必要每一个语句都分析分析,而是应该把重心放在hql语句的业务编写上。
3、修改Fetch操作
Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce盘算。
比方:
在这种情况下,Hive可以简单地读取employee对应的存储目次下的文件,然后输出查询结果到控制台。
在hive-default.xml.template【hive-site.xml】文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
- <property>
- <name>hive.fetch.task.conversion</name>
- <value>more</value>
- <description>
- Expects one of [none, minimal, more].
- Some select queries can be converted to single FETCH task minimizing latency.
- Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), lateral views and joins.
- 0. none : disable hive.fetch.task.conversion
- 1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
- 2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
- </description>
- </property>
复制代码 举例阐明:
- hive (default)> set hive.fetch.task.conversion=none;
- hive (default)> select * from emp;
- hive (default)> select ename from emp;
- hive (default)> select ename from emp limit 3;
- (1)把hive.fetch.task.conversion设置成none,然后执行查询语句,都会执行mapreduce程序。
- (2)把hive.fetch.task.conversion设置成more,然后执行查询语句,如下查询方式都不会执行mapreduce程序。
复制代码 4、开启hive的严酷模式【进步了安全性】
防止写的烂sql影响集群,好比 select * from emp;
开启严酷模式以后,以下情况多报SQL错误!
1)分区表不使用分区过滤
select * from emp where day='20231001'
2) 使用order by没有limit过滤
3) 笛卡尔积不允许出现 select * from emp,dept ;
5、JVM重用
Hadoop中有个参数是mapred.job.reuse.jvm.num.tasks,默认是1,表示一个JVM上最多可以次序执行的task数目(属于同一个Job)是1。也就是说一个task启一个JVM ,这样JVM的效率就比较低,需要JVM重用。
好比:编写了一个sql语句,启动多少个mapTask,多少个reduceTask,取决于数据量的大小。
假如启动了100个MapTask,50个ReduceTask, 如果每一个task都启动一个jvm假造机的话,开启和关闭假造机需要消耗时间的。jvm重用就是一个假造机开启以后,执行多个task使命,再关闭。大大进步执行效率。
- <property>
- <name>mapreduce.job.jvm.numtasks</name>
- <value>10</value>
- <description>How many tasks to run per jvm. If set to -1, there is no limit. </description>
- </property>
- 也可以通过:set mapred.job.reuse.jvm.num.tasks=10;进行设置
复制代码 6、分区、分桶以及压缩
7、公道设置map和reduce的数目
公道设置map数目:
1)通常情况下,作业会通过input的目次产生一个大概多个map使命。
重要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小。
一个文件不敷128M,它不是一个片儿吗? 是一个片 --> map使命
一个文件很大,被切割为了好几个片儿,是不是一个片儿对应一个map使命。
2)map数不是越多越好
如果一个使命有许多小文件(远远小于块大小128m),则每个小文件也会被当做一个 片儿,用一个map使命来完成,而一个map使命启动和初始化的时间远宏大于逻辑处理处罚的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。这种情况下就需要淘汰map数目!
3)每个map处理处罚靠近128m的文件块,也不一定就算完美
好比有一个127m的文件,正常会用一个map去完成,但这个文件只有一个大概两个小字段,却有几千万的记载,如果map处理处罚的逻辑比较复杂,用一个map使命去做,肯定也比较耗时。这种情况下就需要增加map数目。
4)复杂文件增加Map数
当input的文件都很大,使命逻辑复杂,map执行非常慢的时间,可以思量增加Map数,来使得每个map处理处罚的数据量淘汰,从而进步使命的执行效率。
增加map的方法为:根据
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,调解maxSize最大值。即 让最大切片值maxSize最大值低于blocksize就可以增加map的个数。
maxSize = 256M
minSize = 1字节
blocksize = 128M
Math.max(minSize,Math.min(maxSize,blocksize) = 128M
500M--> 128M --> 4 个 map 使命
500M --> 86M --> 大于 4,以是 map 数目增加了
将这个结果变小 -- map数目变多了
Math.max(minSize,Math.min(maxSize,blocksize) =86M
修改maxSize ,让其小于blocksize 大于minSize
maxSize = 86M
将这个结果变大 -- map数目变少了
修改minSize ,让其大于blocksize 小于maxSize
minSize = 200M
Math.max(minSize,Math.min(maxSize,blocksize) = 200M
假如一个使命的数目是500M,一个片假如是128M的话,就启动4个map使命
假如一个片假如是64M,就启动8个map使命,以是片的大小可以决定map的数目。
实战一下:
- 比如:
- hive (default)> select count(*) from emp;
- Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1
- 只有一个Map任务
- 设置最大切片值为100个字节
- hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;
- hive (default)> select count(*) from emp;
- 发现map任务数变为了6个。
- Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 1
复制代码 开启小文件进行合并:
1)在map执行前合并小文件,淘汰map数:CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat没有对小文件合并功能。
- set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
复制代码 2)在Map-Reduce的使命结束时合并小文件的设置
- 在map-only任务结束时合并小文件,默认true
- SET hive.merge.mapfiles = true;
- 在map-reduce任务结束时合并小文件,默认false
- SET hive.merge.mapredfiles = true;
- 合并文件的大小,默认256M
- SET hive.merge.size.per.task = 268435456;
- 当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge
- SET hive.merge.smallfiles.avgsize = 16777216;
复制代码 设置公道的reducer的个数
- 1)调整reduce个数方法一
- (1)每个Reduce处理的数据量默认是256MB
- hive.exec.reducers.bytes.per.reducer=256000000
- (2)每个任务最大的reduce数,默认为1009
- hive.exec.reducers.max=1009
- (3)计算reducer数的公式
- N=min(参数2,总输入数据量/参数1)
- 举例:假如数据量是512M
- 默认启动: 512/256= 2
- 假如我想启动更多的reduce怎么办?
- 可以修改参数1 为 128M ,或者直接修改 参数2 =3 最后启动reduce的数量为3。
- 2)调整reduce个数方法二
- 在hadoop的mapred-default.xml文件中修改
- 设置每个job的Reduce个数
- set mapreduce.job.reduces = 15;
- reduce个数并不是越多越好
- (1)过多的启动和初始化reduce也会消耗时间和资源;
- (2)另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
复制代码 8、设置并行执行
hive会将一个查询转化成一个大概多个阶段(Stage)。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。大概Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含浩繁的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加.
- set hive.exec.parallel=true; //打开任务并行执行
- set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。
复制代码 设置该并行执行的条件是:集群的资源利用率不高的情况下。
9、CBO优化-本钱优化器
Hive 自 0.14.0 开始,加入了一项 "Cost based Optimizer" ,简称CBO,来对 HQL 执行计划进行优化,这个功能通过 "hive.cbo.enable" 来开启。在 Hive 1.1.0 之后,这个属性是默认开启的,它可以自动优化HQL中多个Join的次序,并选择符合的Join算法。
CBO,本钱优化器,代价最小的执行计划就是最好的执行计划。传统的数据库,本钱优化器做出最优化的执行计划是依据统计信息来盘算的。
实战:
- set hive.cbo.enable=true;
- set hive.compute.query.using.stats=true;
- set hive.stats.fetch.column.stats=true;
- set hive.stats.fetch.partition.stats=true;(这个设置在Hive 3.0.0以后就被删除了)
复制代码 10、谓词下推
所谓的谓词下推就是将where条件提前执行,好比先执行where过滤数据在进行join关联表的表。
好比 student teacher 关联 假如只需要男生的数据,可以先过滤出来男生在跟teacher表关联
概念:所谓的谓词简单明白为where反面的条件,所谓谓词下推,就是包管结果精确的条件下,将SQL语句中的where谓词逻辑都尽可能提前执行,淘汰卑鄙处理处罚的数据量。
操作:对应逻辑优化器是PredicatePushDown,配置项为hive.optimize.ppd,默认为true。
好处:通过谓词下推,过滤条件将在map端提前执行,淘汰了map端的输出,降低了数据IO,节约资源,提拔性能。
举例阐明:
-- 创建一个大表:
create table bigtable(
id bigint,
t bigint,
uid string,
keyword string,
url_rank int,
click_num int,
click_url string)
row format delimited fields terminated by '\t';
-- 导入数据
load data local inpath '/home/hivedata/bigtable' into table bigtable;
--打开谓词下推优化属性
hive (yhdb)> set hive.optimize.ppd = true; #谓词下推,默认是true
-- 测试先关联两张表,再用where条件过滤
hive (yhdb)> select o.id from bigtable b join bigtable o on o.id = b.id where o.id <= 10;
Time taken: 3.648 seconds, Fetched: 1081 row(s)
-- 通过子查询后,再关联表
hive (yhdb)> select b.id from bigtable b join (select id from bigtable where id <= 10 ) o on b.id = o.id;
Time taken: 2.675 seconds, Fetched: 1081 row(s)
11、小表Join大表-使用MapJoin
小表Join大表:Map Join 小表缓存并发送到各个节点,没有Shuffle的过程
将key相对分散,而且数据量小的表放在join的左边,这样可以有效淘汰内存溢堕落误发生的几率;再进一步,可以使用map join让小的维度表(1000条以下的记载条数)先进内存。在map端完成join.
如果不指定MapJoin大概不符合MapJoin的条件,那么Hive剖析器会将Join操作转换成Common Join,即:在Reduce阶段完成Join。容易发生数据倾斜。可以用MapJoin把小表全部加载到内存在Map端进行Join,避免Reducer处理处罚。
总结:
1)mapjoin --只有map没有reduce,当然也不会有shuffle
2) common join (shuffle join) : 就是平常的join,走MR步调
select * from dept join emp on emp.detpno = dept.deptno;
实战:
- 实战设置:
- (1)设置自动选择Mapjoin
- set hive.auto.convert.join = true; 默认为true
- (2)大表小表的阈值设置(默认25M以下认为是小表):
- set hive.mapjoin.smalltable.filesize = 25000000;
- 一般情况下:小表放在join的左边,大表放右边,但是新版本的hive,放左放右无所谓了,它会自动优化。
- hive的查询永远是小表(结果集)驱动大表(结果集)
- hive中的on的条件只能是等值连接。
复制代码 12、大表和大表 SMB Join
SMB: sort merge bucket join
- hive 的三种join
- 1、ReduceJoin 也叫 Common Join、Shuffle Join
- 2. MapJoin
- 3. Sort Merge Bucket Join(分桶表Join)
复制代码- -- 再创建一个大表
- hive(default)> create table bigtable2(
- id bigint,
- t bigint,
- uid string,
- keyword string,
- url_rank int,
- click_num int,
- click_url string)
- row format delimited fields terminated by '\t';
- -- 加载数据
- hive(default)> load data local inpath '/home/hivedata/bigtable' into table bigtable2;
- -- 创建join表
- create table jointable(
- id bigint,
- t bigint,
- uid string,
- keyword string,
- url_rank int,
- click_num int,
- click_url string)
- row format delimited fields terminated by '\t';
- -- 测试两个大表直接join: 此处花费时间非常的长
- insert overwrite table jointable
- select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
- from bigtable s
- join bigtable2 b
- on b.id = s.id;
- -- 创建两个分桶表,并导入数据
- create table bigtable_buck1(
- id bigint,
- t bigint,
- uid string,
- keyword string,
- url_rank int,
- click_num int,
- click_url string)
- clustered by(id)
- sorted by(id)
- into 2 buckets -- 桶的个数和CPU核数和Reduce数需要一致
- row format delimited fields terminated by '\t';
- -- 导入第一个分桶表
- insert into bigtable_buck1 select * from bigtable;
- -- 创建第二个分桶表
- create table bigtable_buck2 like bigtable_buck1;
- -- 导入数据
- insert into bigtable_buck2 select * from bigtable;
- --开启SMB设置
- hive(yhdb)> set hive.optimize.bucketmapjoin = true;
- hive(yhdb)> set hive.optimize.bucketmapjoin.sortedmerge = true;
- hive(yhdb)> set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
- -- 两张大表关联
- hive(yhdb)> insert overwrite table jointable
- select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
- from bigtable_buck1 s
- join bigtable_buck2 b
- on b.id = s.id;
- -- 对比两种方式总耗时时间,前提是需要进行分布式计算,不要在伪分布或本地模式下计算。
复制代码- 假如有两个大表,如何join速度快,就是创建两个分桶表表,把大表的数据导入进去,然后让分桶表和分桶表进行join,速度会快,当然在执行之前,需要开启smb join的设置。
复制代码 13、可以在hive表上创建索引【了解】
索引:着实就是作用在数据库的一种算法,以mysql为例:
- create table stu(
- id int,
- name varchar(20),
- INDEX idx_name (id)
- )
复制代码 在某一个大概多个字段上添加索引,好处就是假如你的sql语句使用到了索引字段,查询速度会很快!
总而言之好处是进步查询效率。不加索引是自行车,加了索引是火箭!
索引不是越多越好,而是根据实际情况而定:
1、经常查询的字段加索引
2、多个表经常关联的字段加索引
select * from emp ,dept where emp.deptno= dept.deptno;
3、主键自然是索引
4、一个表中假如有20个字段的话,最多4~5个字段加索引。
添加索引查询速度变快,插入速度变慢
- CREATE INDEX index_student2_class_id
- ON TABLE student2 (class_id)
- AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
- WITH DEFERRED REBUILD
- IDXPROPERTIES ('creator' = 'yhbigdata','created_at' = '2023-02-22 18:00:00')
- IN TABLE INDEX index_student2_class_id_table
- COMMENT 'index_student2';
- 假如以后的sql语句中出现class_id ,查询速度就变快了。
- 还需要进行设置才可以使用:
- SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;
- SET hive.optimize.index.filter=true;
- hive的索引仅供参考,因为hive在3.0版本已经被删除,参考文献:
- https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Indexing#LanguageManualIndexing-IndexingIsRemovedsince3.0
复制代码 14、列裁剪与分区裁剪
sql语句在进行查询的时间不要全部查询,使用哪个字段就查询哪个字段,不要动不动就 * ;
需要哪个分区就查询哪个分区,不要全查。
列裁剪就是在查询时只读取需要的列,分区裁剪就是只读取需要的分区。当列许多大概数据量很大时,如果 select * 大概不指定分区,全列扫描和全表扫描效率都很低。
Hive 在读数据的时间,可以只读取查询中所需要用到的列,而忽略其他的列。这样做可以节省读取开销:中间表存储开销和数据整合开销。
-- 列裁剪
select name,age from emp;
-- 分区裁剪
select * from emp where dept='技能部';
15、避免数据倾斜
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|