Hive的基本使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28844767/article/details/80608860

Hive的简单操作:

1、创建库:

create database mydb;

2、查看库:

show databases;

3、切换数据库:

use mydb;

4、创建表:

 create table t_user(id string, name string);
或create table student(id string, name string, sex string, dept string) row format delimited fields terminated by ',';

5、插入数据:

insert into table t_user values ("002","xiaoma");

6、查询数据:

select * from t_user;

7、导入数据:

  • 导入HDFS数据:
load data inpath '/hive/student.txt' into table student;
  • 导入本地数据:
load data local inpath '/home/hadoop/student.txt' into table student;

Hive基本操作:

  1. DDL操作:       

扫描二维码关注公众号,回复: 2975518 查看本文章
  • 库操作
  • 创建库

    语法结构:

CREATE(DATABASE|SCHEMA)[IF NOT EXIST] database_name
    [COMMENT database_comment]
    [LOCALTION hdfs_path]
    [WITH DBPROPERTIES (property_name=property_value,...)];

创建库的使用方式:

1、创建普通库:

create database dbname;

2、创建库的时候检查存与否:

create database if not exists dbname;

3、创建库的时候带注释:

create database if not exists dbname comment 'create my db name dbname';

4、创建带属性的库:

create database if not exists dbname with dbproperties('a'='aaa','b'='bbb');
  • 查看库

1、查看有哪些数据库:

show databases;

2、显示数据库的详细属性信息:

语法: desc database [extended] dbname;
示例: desc database extended myhive;

3、查看正在使用哪个库:

select current_database();

4、查看创建库的详细语句:

show create database mydb;
  • 删除库

删除库操作:

drop database dbname;
drop database if exists dbname;

默认情况下,hive不允许删除包含表的数据库,有两种解决办法:

    1、手动删除库下所有表,然后删除库

    2、使用 cascade 关键字

drop database if exists dbname cascade;

    默认情况下就是restrict

drop database if exists myhive == drop database if exists myhive restrict
  • 切换库    

    切换库操作:

 语法:    use database_name;
 实例:    use myhive;
  • 表操作
  • 创建表

    1、建表语句

        语法结构:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
    [(col_name data_type [COMMENT col_comment],...)]
    [COMMENT table_comment]
    [PARTITIONED BY (col_name data_type [COMMENT col_comment],...)]
    [CLUSTERED BY (col_name, col_name,...)
    [SORTED BY (col_name [ASC|DESC],...)] INTO num_buckets BUCKETS]
    [ROW FORMAT row_format]
    [STORED AS file_format]
    [LOCATION hdfs_path]

    2、建表语句相关解释

    CREATE TABLE: 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。

    EXTERNAL: 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),如果不存在,则会自动创建该目录。Hive创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。

    PARTITIONED BY 在Hive Select查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作。有时候只需要扫描表中关心的一部分数据,因此建表是引入partition概念。一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下,分区是以字段的形式在表结构中存在,通过desc table 命令可以查看到字段存在,但是该字段不存放实际的数据内容,仅仅是分区的表示。

    分区建表为2种:

    一种是单分区,也就是说在表文件夹目录下只有一级文件夹目录

    一种是多分区,表文件夹下出现多文件夹嵌套模式

    LIKE: 允许用户复制现有的表结构,但是不复制数据。

示例: create table tableA like tableB (创建一张tableA空表复制tableB的结构)
    COMMENT:可以为表与字段增加描述

    ROW FORMAT

    DELIMITED [FIELDS TERMINATED BY char]
              [COLLECTION ITEMS TERMINATED BY char]
              [MAP KEYS TERMINATED BY char]
              [LINES TERMINATED BY char]
|  SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value,property_name=property_value,...)]

用户在建表的时候可以自定义 SerDe 或者使用自带的SerDe。如果没有指定ROW FORMAT 或者ROW FORMAT DELIMITED,将会使用自带的SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的SerDe,Hive通过SerDe确定表的具体的列的数据。

    STORED AS TEXTFILE | SEQUENCEFILE | RCFILE

    如果文件数据是纯文本,可以使用 STORED AS TEXTFILE,默认也是textFile格式,可以通过执行命令 set hive.default.fileformat,进行查看,如果数据需要压缩,使用STORED AS SEQUENCEFILE。

    1、默认格式TextFile,数据不做压缩,磁盘开销大,数据解析开销大。可结合gzip,bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分。从而无法对数据进行并行操作

    2、SequenceFile 是Hadoop API提供的一种二进制文件支持,文件内容是以序列化的kv对象来组织的,其具有使用方便、可分割、可压缩的特点。SequenceFile支持三种压缩选择: NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩

    RCFILE是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。数据仓库的特点是一次写入,多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势

    CLUSTERED BY

    对于每一个表(table)或者分区,Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是针对某一列进行桶的组织。Hive采用对列值hash,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。

    把表(或者分区)组织成桶(Bucket)有两个理由:

    1、获得更高的查询处理效率。桶为表加上了额外的结构,Hive在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用Map端连接(Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大减少JOIN的数据量。

    2、使取样(samping)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。

    LOCATION : 指定数据文件存放的HDFS目录,不管内部表还是外部表,都可以指定。不指定就在默认的仓库路径。

3、Hive建表示例:

CREATE TABLE page_view(viewTime INT, userid BIGINT, page_url STRING, referrer_url STRING, ip STRING COMMENT 'ip Address of the User')
    COMMENT 'This is the page view table'
    PARTITIONED BY (dt STRING, country STRING)
    CLUSTERED BY(userid) SORTED BY(viewTime) INTO 31 BUCKETS
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '\t'
    COLLECTION ITEMS TERMINATED BY '\t'
    MAP KEYS TERMINATED BY '\t'
    LINES TERMINATED BY '\n'
    STORED AS TEXTFILE
    LOCATION '/user/hive/warehouse/mydb.db'

执行命令查看表结构:

desc formatted page_view;
# col_name              data_type               comment             
                 
viewtime                int                                         
userid                  bigint                                      
page_url                string                                      
referrer_url            string                                      
ip                      string                  ip Address of the User
                 
# Partition Information          
# col_name              data_type               comment             
                 
dt                      string                                      
country                 string                                      
                 
# Detailed Table Information             
Database:               mydb                     
Owner:                  hadoop                   
CreateTime:             Thu Jun 07 19:22:00 CST 2018     
LastAccessTime:         UNKNOWN                  
Retention:              0                        
Location:               hdfs://hadoop01:9000/user/hive/warehouse/mydb.db    
Table Type:             MANAGED_TABLE            
Table Parameters:                
        COLUMN_STATS_ACCURATE   {\"BASIC_STATS\":\"true\"}
        comment                 This is the page view table
        numFiles                0                   
        numPartitions           0                   
        numRows                 0                   
        rawDataSize             0                   
        totalSize               0                   
        transient_lastDdlTime   1528370520          
                 
# Storage Information            
SerDe Library:          org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe      
InputFormat:            org.apache.hadoop.mapred.TextInputFormat         
OutputFormat:           org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat       
Compressed:             No                       
Num Buckets:            31                       
Bucket Columns:         [userid]                 
Sort Columns:           [Order(col:viewtime, order:1)]   
Storage Desc Params:             
        colelction.delim        \t                  
        field.delim             \t                  
        line.delim              \n                  
        mapkey.delim            \t                  
        serialization.format    \t                  

Hive使用一个Inputformat对象将输入流分割成记录;使用一个Outputformat对象将记录格式化为输出流,使用序列化/反序列化器SerDe做记录的解析(记录和列的转换)。

默认值分别是:

Inputformat: org.apache.hadoop.mapred.TextInputFormat

Outputformat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat

SerDe: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe

4、具体实例:

a、创建内部表

create table mytable(id int, name string)
row format delimited fields terminated by ',' stored as textfile;


b、创建外部表

create external table mytable2(id int, name string)
row format delimited fields terminated by ',' location '/user/hive/warehouse/mydb.db';



c、创建分区表

create table mytable3(id int, name string) partitioned by (sex string)
row format delimited fields terminated by ',' stored as textfile;



插入数据:

插入男分区数据: load data local inpath '/home/hadoop/sex.txt' overwrite into table mytable3 partition(sex='boy')
插入女分区数据: load data local inpath '/home/hadoop/sex.txt' overwrite into table mytable3 partition(sex='girl');


查询表分区:

show partitions mytable3;

d、创建分桶表

create table stu_buck(Sno int, Sname string, Sex string, Sage int, Sdept string)
clustered by(Sno) sorted by(Sno DESC) into 4 buckets
row format delimited fields terminated by ',';

e、使用like关键字拷贝表

不管老表是内部表还是外部表,new_table都是内部表

create table new_table like mytable;

不管老表是内部表还是外部表,如果加external关键字,new_table都是外部表

create external table if not exists new_table like mytable;
  • 修改表

    1、重命名表

    语法结构:

ALTER TABLE table_name RENAME TO new_table_name

    示例:

alter table student rename to new_table_name;

2、修改表属性

    语法结构:

ALTER TABLE table_name SET TBLPROPERTIES table_properties;
table_properties:(property_name=property_value,...)

示例:

ALTER TABLE new_table_name SET TBLPROPERTIES('comment'='my new students table');
查看:
desc formatted new_table_name;

3、修改SerDe信息

    语法结构:

ALTER TABLE table_name [PARTITION partition_spec] SET SERDE serde_class_name [WITH SERDEPROPERTIES serde_properties];
ALTER TABLE table_name [PARTITION partition_spec] SET SERDEPROPERTIES serde_properties;
serde_properties:(property_name=property_value,...)

示例:

更改列分隔符: ALTER TABLE student SET SERDEPROPERTIES('field.delim'='-');

4、增加/删除/改变/替换列

    语法结构:

ALTER TABLE name ADD COLUMNS(col_spec,[col_spec...])
ALTER TABLE name CHANGE c_name new_name new_type [FIRST|AFTER c_name]
ALTER TABLE name REPLACE COLUMNS(col_spec,[col_spec ...])

注意:ADD是代表新增一字段,字段位置在所有列后面(partition列前),REPLACE则是表示替换表中所有字段。

ADD示例:


CHANGE示例:


REPLACE示例:


5、增加/删除分区

    增加分区语法结构:

ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec [LOCALTION 'locayion1'] partition_spec [LOCALTION 'location2']...

partition_spec:PARTITION(partition_col1 = partition_col_value1,partition_col2 = partition_col_value2,...)

删除分区语法结构:

ALTER TABLE table_name DROP partition_spec, partition_spec,...

添加分区示例:

// 不指定分区路径,默认路径
ALTER TABLE mytable3 ADD partition(sex='null');

// 指定分区路径
ALTER TABLE mytable3 ADD IF NOT EXISTS partition(sex='test')location '/user/hive/warehouse/mydb.db/mytable3/test'


// 修改分区路径示例
ALTER TABLE mytable3 partition(sex='test') SET location '/user/hive/warehouse/mydb.db/mytable3/test1';

//删除分区示例
ALTER TABLE mytable3 DROP if exists partition(sex='null');
ALTER TABLE mytable3 DROP if exists partition(sex='null') if exists partition(sex='test');

最后补充:

1、防止分区被删除:
alter table mytable3 partition(sex='boy') enable no_drop;
2、防止分区被查询:
alter table mytable3 partition(sex='girl') enable offline;
enable和disable是反向操作
  • 删除表

语法结构:

DROP TABLE [IF EXISTS] table_name;

命令:

drop table if exists mytable;

  • 清空表

语法结构:

TRUNCATE TABLE table_name [PARTITION partition_spec];

示例:

truncate table student;
truncate table mytable3 partition(sex='boy');


  • 其他辅助命令
    show databases;
    show databases like 'my*';
    查看数据库列表
    show tables;
    show tables in db_name;
    查看数据表
    show create table table_name; 查看数据表的建表语句
    show functions; 查看hive函数列表
    show partitions table_name;
    show partitions table_name partition(city='beijing')
    查看hive表的分区
    desc table_name;
    desc extended table_name;
    desc formatted table_name;
    查看表的详细信息(元数据信息)
    desc database db_name;
    desc database extended db_name;
    查看数据库的详细属性信息
    truncate table table_name; 清空数据表
  • DML操作
  • Load装载数据

语法结构:

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION(partcol1=val1,partcol2=val2 ...)] 

说明:

1、LOAD 操作只是单纯的复制或者移动操作,将数据文件移动到Hive表对应的位置。

2、LOCAL关键字:

        如果指定了LOCAL,LOAD命令会去查找本地文件系统中的filepath。

        如果没有指定LOCAL关键字,则根据inpath中的uri查找文件

        注意: uri是指定hdfs上的路径,分简单模式和完整模式两种,例如:

        简单模式:    /usr/hive/project/data1

        完整模式:    hdfs://namenode_host:9000/user/hive/project/data1

3、filepath:

        相对路径,例如: project/data1

        绝对路径,例如: /user/home/project/data1

        包含模式的完整URI,例如: hdfs://namenode_host:9000/user/home/project/data1

        注意:inpath子句中的文件路径下,不能再有文件夹。

4、overwrite 关键字

        如果使用了 OVERWRITE 关键字,则目标表(或者分区)中的内容会被删除,然后再将filepath指向的文件/目录中的内容添加到表/分区中。

        如果目标表(分区)已经有一个文件,并且文件名和filepath中的文件名冲突,那么现有的文件会被新文件所替代。

具体实例:

1、加载本地相对路径数据


2、加载绝对路径数据


3、加载包含模式数据


4、overwrite关键字使用


  • 2.2 Insert 插入数据

    语法结构:

1、插入一条数据:

INSERT INTO TABLE table_name VALUES(XX,YY,ZZ);

2、利用查询语句将结果导入新表:

INSERT OVERWRITE [INTO] TABLE table_name [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement

3、多重插入:

FROM from_statement
INSERT OVERWRITE TABLE table_name1 [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement1
INSERT OVERWRITE TABLE table_name2 [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement2 ...

示例:

from mingxing
insert into table mingxing2 select id, name, sex, age
insert into table mingxing select id, name, sex, age, department;
从mingxing表中,按不同的字段进行查询得的结果分别插入不同的hive表

from student
insert into table ptn_student partition(city='MA') select id, name, sex, age, department where department='MA';
insert into table ptn_student partition(city='IS') select id, name, sex, age, department where department='IS';
insert into table ptn_student partition(city='CS') select id, name, sex, age, department where department='CS';

4、分区插入:

分区插入有两种,一种是静态分区,另一种是动态分区。如果混合使用静态分区和动态分区,则静态分区必须出现在动态分区之前。现在分别介绍这两种分区插入。

静态分区:

    A)、创建静态分区表

    B)、从查询结果中导入数据

    C)、查看插入结果

动态分区:

静态分区需要创建非常多的分区,那么用户就需要写非常多的SQL! Hive提供了一个动态分区功能,其可以基于查询参数推断出需要创建的分区名称。

    A)、创建分区表,和创建静态分区表是一样的

    B)、参数设置

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

注意:动态分区默认情况下是开启的。但是却以默认是“strict”模式执行的,在这种模式下要求至少有一列分区字段是静态的。这有助于阻止因设计错误导致查询产生大量的分区。但是此处我们不需要静态分区字段,故将其设为nonstrict。

对应还有一些参数可设置:

set hive.exec.max.dynamic.partitions.pernode=100; // 每个节点生成动态分区最大个数
set hive.exec.max.dynamic.partitions=1000; //生成动态分区最大个数,如果自动分区数大于这个参数,将会报错
set hive.exec.max.created.files=100000; // 一个任务最多可以创建的文件数目
set dfs.satanode.max.xcievers=4096; //限定一次最多打开的文件数
set hive.error.on.empty.partition=false; //表示当有空分区产生时,是否抛出异常

小技能补充:如果以上参数被更改过,想还原,请使用reset命令执行一次即可

C)、动态数据插入

//一个分区字段:
insert into table test2 partition(age) select name,address,school,age from students;

// 多个分区字段:
insert into table student_ptn2 partition(city='sa',zipcode) select id, name, sex, age, department as zipcode from students;

注意: 查询语句select查询出来的动态分区age和zipcode必须放最后,和分区字段对应,不然结果会出错

D)、查看插入结果

select * from student_ptn2 where city='sa' and zipcode='MA';

5、CTAS(create table ... as select ...)

    在实际情况中,表的输出结果可能太多,不适于显示在控制台上,这时候,将Hive的查询输出结果直接存在一个新的表中是非常方便的,我们称这种情况为CTAS

展示: CREATE TABLE mytest AS SELECT name, age FROM test;
注意:CTAS操作是原子的,因此如果select查询由于某种原因而 失败,新表是不会创建的!
  • 2.3、Insert导出数据

单模式导出:

INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement

多模式导出:

FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...

具体实例:

1、导出数据到本地:

insert overwrite local directory '/root/hivedata/student.txt' select * from students;

注意: 数据写入到文件系统时进行文本序列化,且每列用^A来区分,\n为换行符。用more命令查看时不容易看出分隔符,可以使用: sed -e 's/\x01/\t/g' filename 来查看。

2、导出数据到HDFS

insert overwrite directory '/student' select * from students where age >= 20;
isnert overwrite directory 'hdfs://hadoop02:9000/user/hive/warehouse/mystudent' select * from students;
  • 2.4、Select 查询数据

Hive中的SELECT基础语法和标准SQL语法基本一致,支持WHER、DISTINCT、GROUP BY、ORDER BY、 HAVING、 LIMIT、子查询等;

1、 select * from db.table1;
2、 select count(distinct uid) from db.table1;
3、 支持select、union all、join(left、right、full join)、like、where、having、各种聚合函数、支持json解析
4、UDF(User Defined Function)/UDAF/UDTF
5、不支持update和delete
6、hive虽然支持in/exists(老版本是不支持的),但是hive推荐使用semi join的方式来代替实现,而且效率更高。
7、支持case... when ...

语法结构:

SELECT [ALL|DISTINCT] select_condition,select_condition,...
FROM table_name a
[JOIN table_other b ON a.id = b.id]
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list | ORDER BY col_list]]
[LIMIT number]

说明:

1、 select_condition 查询字段

2、 table_name 表名

3、order by(字段) 全局排序,因此只有一个reducer,只有一个reduce task的结果,比如文件名是000000_0,会导致当输入规模较大时,需要较长的计算时间。

4、sort by(字段) 局部排序,不是全局排序,其在数据进入reducer前完成排序。因此,如果sort by进行排序,并且设置mapred.reduce.tasks>1,则sort by只保证每个reducer的输出有序,不保证全局有序。

那万一,我要对我的所有处理结果进行一个综合排序,而且数据量又非常大,那么怎么解决?我们不适用order by 进行全数据排序,我们适用sort by对数据进行局部排序,完了之后,再对所有的局部排序结果做一个归并排序

5、distribute by(字段) 根据指定的字段将数据分到不同的reducer,且分发算法是hash散列。

6、cluster by(字段) 除了具有Distribute by的功能外,还会对该字段进行排序。

因此,如果分桶和sort字段是同一个时,此时,cluster by = distribute by + sort by

如果我们要分桶的字段和要排序的字段不一样,那么我们就不能使用cluster by

分桶表的作用:最大的作用是用来提高join操作的效率;

(思考这个问题:select a.id,a.name,b.addr from a join b on a.id = b.id; 如果a表和b表已经是分桶表,而且分桶的字段是id字段做这个join操作时,还需要全表做笛卡尔积吗?)

实例:

1、获取年龄大的三个学生

select id, age, name from student where stat_date='20140101'order by age desc limit 3;

2、查询学生年龄按降序排序

set mapred.reduce.tasks=4;
select id, age, name from student sort by age desc;

select id, age, name from student order by age desc;

select id, age, name from student distribute by age;

这是分桶和排序的组合操作,对id进行分桶,对age,id进行降序排序

insert overwrite directory '/root/outputdata6' select * from mingxing2 distribute by id sort by ae desc,id desc;

这是分桶操作,按照id分桶,但是不进行排序

insert overwrite directory '/root/outputdata4' select * from mingxing2 distribute by id sort by age;

这是分桶操作,按照id分桶,并且按照id排序

insert overwrite directory '/root/outputdata3' select * from mingxing2 cluster by id;

分桶查询:

指定开启分桶:

set hive.enforce.bucketing=true;

指定reducetask数量,也就是指定桶的数量

set mapreudce.job.reduces=4;
insert overwrite directory '/root/outputdata3' select * from mingxing2 cluster by id;

3、按学生名称汇总学生年龄

select name, sum(age) from student group by name;

总结:

一、解释三个执行参数

In order to change the average load for a reducer(in bytes):
  set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximun number of reducers:
  set hive.exec.reducers.max=<number>
In order to set a constant number of reducers:
  set mapreduce.job.reduces=<number>

1、直接使用不带设置值的时候是可以查看到这个参数的默认值:

set hive.exec.reducers.bytes.per.reducer

hive.exec.reducers.bytes.per.reducer: 一个hive,就相当于一次hive查询中,每一个reduce任务它处理的平均数据量
如果要改变值,我们使用这种方式:
set hive.exec.reducer.bytes.per.reducer=51200000

2、查看设置的最大的reducetask数量

set hive.exec.reducers.max
hive.exec.reducers.max:一次hive查询中,最多使用的reduce task的数量
我们可以这样使用去改变这个值:
set hive.exec.reducers.max=20

3、查看设置的一个reducetask数量

set mapreduce.job.reduces
mapreduce.job.reduces: 我们设置的reducetask数量

二、HQL是否被转换成MR的问题

前面说过,HQL语句会被转换成MapReduce程序执行,但是上面的例子可以看出部分HQL语句并不会转换成MapReduce,那么什么情况下可以避免转换呢?

1、select * from student; //简单读取表中文件数据时不会
2、where过滤条件中只是分区字段时不会转换成MapReduce
3、set hive.exec.mode.local.auto=true; //hive会尝试使用本地模式执行,否则,其他情况都会被转换成MapReduce程序执行
  • 2.5 Hive Join 查询

语法结构:

join_table:
  table_reference JOIN table_factor [join_condition]
  | table_reference {LEFT|RIGHT|FULL}[OUTER] JOIN table_reference join_condition
  | table_reference LEFT SEMI JOIN table_reference join_condition

Hive支持等值连接(equality join)、外连接(outer join)和(left/right join)。Hive不支持非等值的连接,因为非等值连接非常难转化到map/reduce任务。

另外,Hive支持多于2个表的连接。

写查询时要注意以下几点:

1、只支持等值连接,支持and,不支持or

例如:
SELECT a.* FROM a JOIN b ON (a.id = b.id);
SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)
是正确的;
然而:SELECT a.* FROM a JOIN b ON (a.id > b.id)是错误的。

2、可以join多于2个表

例如:

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

如果join中的多个表的join key 是同一个,则join会被转化为单个 map/reduce任务,例如:

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

被转化为单个map/reduce任务,因为join中只使用了b.key1 作为join key。

例如:SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
而这一join被转化为2个,map/reduce 任务。因为b.key1 用于第一次join条件,而b.key2用来第二次join。


3、join时,每次map/reduce任务的逻辑

reducer会缓存join序列中除了最后一个表的所有表的记录,再通过最后一个表将结果序列化到文件系统。这一实现有助于在reduce端减少内存的使用量。实践中,应该把最大的那个表写在最后(否则会因为缓存浪费大量内存)。

例如:

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

所有表都使用同一个join key(使用1次map/reduce任务计算)。Reduce端会缓存a表和b表的记录,然后每次取得一个c表的记录就计算一次join结果,类似的还有:

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

这里用了2次map/reduce任务:

第一次缓存a表,用b表序列化;

第二次缓存第一次map/reduce任务的结果,然后用c表序列化。

4、 HiveJoin 分三种: inner join, outer join, semi join

其中: outer join 包括 left join, right join 和 full outer join, 主要用来处理join中空记录的情况

    1、创建两张表:

create table tablea(id int, name string) row format delimited fields terminated by ',';
create table tableb(id int, age int) row format delimited fields terminated by ',';

    2、准备数据

    3、分别导入数据a.txt到tablea表,b.txt到tableb表

    4、数据准备完毕

load data local inpath '/home/hadoop/a.txt' into table tablea;
load data local inpath '/home/hadoop/b.txt' into table tableb;

    5、join演示

    a)、inner join(内连接)(把符合连接条件的数据查询出来)

select * from tablea a inner join tableb b on a.id=b.id;

    b)、left join (左连接,等同于left outer join)

    1、以左表数据为匹配标准,左大右小

    2、匹配不上的就是null

    3、返回的数据条数与左表相同

    HQL语句:

select * from tablea a left join tableb b on a.id = b.id;
    c)、right join(右连接,等同于 right outer join)

    1、以右表数据为匹配标准,左小右大

    2、匹配不上的就是null

    3、返回的数据条数与右表相同

    HQL语句:

select * from tablea a right join tableb b on a.id = b.id;

    e)、left semi join(左半连接)(因为hive不支持in/exists操作(1.2.1版本的hive支持 in的操作),所以用该操作实现,并且是in/exists的高效实现)

select * from tablea a left semi join tableb b on a.id = b.id;

    f)、full outer join(完全外连接)

select * from tablea a full outer join tableb b on a.id = b.id;


猜你喜欢

转载自blog.csdn.net/qq_28844767/article/details/80608860
今日推荐