Hive的基本操作(三)

Hive的基本操作(三)

1.DDL操作

Hive的hql语句支持SQL一般语法,大致与SQL相似。

SQL语言包括四种主要程序设计语言类别的语句:

数据定义语言(DDL),数据操作语言(DML),数据控制语言(DCL)和事物控制语言(TCL)

DDL(Data Definitition Language):数据库模式定义语言

1.1.库操作

1.创建库:

CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name

[COMMENT database_comment]  //创建库带注释

[LOCATION hdfs_path]

[WITH DBPROPERTIES (property_name=property_value, ...)]; //创建库指定属性

create databases dbname;   /  create databases if not exists dbname;

创建库的时候带注释:create database if not exists dbname comment 'create my db named dbname';

创建带属性的库 create database if not exists dbname with dbproperties ('a'='aaa','b'='bbb');

2.查看库

查看所有库:show databases;

显示数据库的详细属性信息 语法:desc database [extended] dbname;

查看正在使用哪个库:select current_database();

3.删除库

删除库操作: 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

4.切换库操作: 语法:use database_name

1.2.表操作

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]    //指定表的数据存储路径 

语法解析:

默认建表为内部表 ,加关键字EXTERNAL,新建为外部表,在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删 除数据。(ps:公共数据一般都是用外部表)

表的数据存储路径都是可以通过 location 指定的!!!!!!

推荐方式: 1、 创建内部表的时候,最好别指定 location,就存储在默认的仓库路径 2、 如果要指定外部路径,那么请创建该表为外部表

PARTITIONED BY:建分区表关键字

CLUSTERED BY :建分桶表关键字  [SORTED BY (col_name [ASC|DESC], ...)]  指定每个桶的排序规则INTO num_buckets BUCKETS]  分的桶的个数 

[ROW FORMAT row_format] 指定分割符

列分割符:fields terminated by ' , ' 

行分割符:lines terminated by ' , '

元素分割符:items terminated by ' , '

[STORED AS file_format]  指定表中读取文件的类型 默认 textfile

textfile 文本格式    rcfile 行列存储相结合的存储方式   sequencefile 二进制文件格式

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

最佳实践: 如果创建内部表请不要指定 location 如果创建表时要指定 location,请创建外部表。

列举四个类型表的建表示例:

内部表:

create table if not exists student(id int,name string,sex string,age int,department string) row format delimited fields terminated by ',' STORED as textfile ; //若指定了hdfs存储路径,则会覆盖配置文件中默认设置的目录路径

外部表:

create external table if not exists student_ext(id int,name string,sex string,age int,department string) row format delimited fields terminated by ',' STORED as textfile location '/hivetest' ;

分区表:
                             create external table if not exists student_ptn (id int,name string,sex string,age int) partitioned by (department string) row format delimited fields terminated by ',';  // ps:分区字段一定不能再建表字段中出现
                             //添加分区 IS FM
                             alter table student_ptn add partition (department='IS')  partition (department='FM');

(ps:分区表作用:减少扫描范围  提升查询性能)

分桶表:

create external table if not exists student_bk (id int,name string,sex string,age int,department string) CLUSTERED BY (age) SORTED BY (id desc) INTO 3 BUCKETS row format delimited fields terminated by ','; //指定分3个桶,分桶字段一定要在建表字段中出现
                       默认分桶规则  age.hashcode()%3  ----0    bucket0      ---1    bucket1    -----2    bucket2

(ps:分桶表作用:1.提升抽样性能 使取样更高效, 2. 提升join的性能,获得更高的查询处理效率)

cats:

create table tablename as select ...... from ...
           create table stu_ctas as select id,name,age from student01;    

复制表:like关键字

仅仅复制表结构 不复制表的数据
            表的存储路径在默认的路径下
            create table stu_copy like student01;

2.查看表

show tables;
            show tables in db;查看指定数据库下的表列表
            show tables like ' ' ; 模糊查询

desc student_ptn;查看表的字段信息
            desc extended student_ptn;  查看表的详细信息
            desc formatted student_ptn;  查看表的详细信息   格式化
             show partitions student_ptn;   查看表的分区

3.修改表

修改表名称:
                    alter table student01 rename to stu_new;
                修改表字段:
                    添加一个列:
                        alter table stu_copy_new add columns(city string,family int);
                    修改一个列:
                        alter table stu_copy_new change family home int;   改列名称
                        alter table stu_copy_new change home home string; 改类型
                        alter table stu_copy_new change city city int;
                        hive2.3.2版本中
                        修改类型的时候一定注意  小类型----大类型改    大类型不可以改为小类型
                        int-string   可以   string--int不可以
                        hive1.2.2版本中数据类型可以随便改的,

         替换列:所有列   
                        alter table stu_copy_new replace columns (name int,ss string);
                        alter table stu_copy_new replace columns (id int);

   修改分区表的分区:
                    添加分区:
                        alter table student_ptn add partition(department='aa') partition(department='bb');
                    修改分区:修改分区的存储路径
                        1)添加分区的时候指定分区路径
                            alter table student_ptn add partition(department='cc') location '/usr/myhive/ptn';
                        2)修改已经添加的分区的路径
                            alter table student_ptn partition(department='aa') set location '/usr/myhive/ptn01';
                    删除分区:
                        alter table student_ptn drop partition(department='aa');

清空表:仅仅清空表数据   表结构依然保留
                truncate table student01;

4.删除表  drop table student01;

1.3.其他辅助命令

查看数据表
            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; 清空数据表

2.DML操作

 数据操纵语言(Data Manipulation Language, DML)是SQL语言中,负责对数据库对象运行数据访问工作的指令集

2.1. load 装载数据

语法结构:

load data [local] inpath ' filepath ' [overwrite] into table tablename [partition (partcol=val1,partcol=val2......)]

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

2、 LOCAL 关键字 如果指定了 LOCAL, LOAD 命令会去查找本地文件系统中的 filepath。 如果没有指定 LOCAL 关键字,则根据 inpath 中的 uri 查找文件 注意:uri 是指 hdfs 上的路径,分简单模式和完整模式两种,例如: 简单模式:/user/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、从本地进行加载
                load data local inpath '/home/hadoop/apps/stu.txt' into table stu_test01;
                将本地的数据上传到hdfs表的数据存储目录下  本地的数据依然存在
2、从hdfs加载数据
                hdfs本身就存储的有这个数据  当执行这个操作的时候  是移动的过程
                load data inpath '/hive02/stu.txt' into table stu_test01;

3、overwrite 关键字使用

                  load data local inpath '/home/hadoop/apps/stu.txt' overwrite into table stu_test01;

2.2  insert插入数据

语法结构

2.2.1 插入一条数据 insert into table stu_test01 values(1,"zs","f",120,"ycdf");

(ps:这种方式会先创建一个临时表values__tmp__table__1   将插入的数据放在临时表中   后面再从临时表中复制过来,效率极低,不推荐使用)

2.2.2 单重插入

insert into table stu_test02 select .. from ...

使用查询语句进行插入,每次插入数据是一次查询结果,数据每插入一次  对stu_test01扫描一次

例:insert into table stu_test02 select * from stu_test01 where age<=20;

2.2.3  多重插入

 from 原来表名
  insert into table 新表名1 select .....
  insert into table 新表名2 select ....

插入多个查询结果  但是对表扫描仅仅1次

例:from  stu_test01
                insert into table student_ptn01 partition (age=17) select id,name,sex,department where age<18
                insert into table student_ptn01 partition (age=18) select id,name,sex,department where age=18
                insert into table student_ptn01 partition (age=19) select id,name,sex,department where age>18;

2.2.4 分区表的数据插入

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

静态分区: A)、创建静态分区表 B)、从查询结果中导入数据 C)、查看插入结果

不适用的场景:
                    1)分区数量比较多的时候
                    2)不知道分区名,无法确定全部分区名的时候

动态分区: 静态分区需要创建非常多的分区,那么用户就需要写非常多的 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.datanode.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, department as zipcode from studentss;

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

D)、查看插入结果 select * from student_ptn2 where city=’sa’ and zipcode=’MA’;

2.2.5 分桶表的数据插入

 分桶表不支持load方式,分桶表数据的插入需要执行mr程序,而load方式直接将数据和表结构关联,并没有走mr,故不支持

支持insert方式

建表语句:    
            create external table if not exists student_bk (id int,name string,sex string,age int,department string) CLUSTERED BY (age) SORTED BY (id desc) INTO 3 BUCKETS row format delimited fields terminated by ',';
            SORTED BY (id desc)  每一个桶中的排序规则

本文时基于hive2.3.2版本,设置参数:
            set hive.enforce.bucketing=true;(hive1.2.2  需要设置)
            set mapreduce.job.reduces=3;(几个分桶设置成几个)
            set hive.exec.reducers.bytes.per.reducer=<number>   设置每一个reducetask的吞吐量(一次加载数据量)   256000000
            set hive.exec.reducers.max=<number>  设置reducetask的最大运行数量  1009
            set mapreduce.job.reduces=<number>  //设置reducetask实际运行数量    (-1,默认就是1个)

2.2.6、CTAS(create table … as select …)

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

展示:CREATE TABLE mytest AS SELECT name, age FROM test;

注意:CTAS 操作是原子的,因此如果 select 查询由于某种原因而失败,新表是不会创建的!

最后提几点

1>分区表不建议使用load方式(当你十分确定数据格式以及数据的完整性,没有脏数据时,可以使用),分桶表不支持load方式

2>分区表的数据查询的问题:
                分区表进行数据查询的时候讲分区字段看做普通字段(过滤条件字段)进行查询
                select * from student_ptn01 where age=18;//查询分区为18的分区中的数据  仅仅扫描分区号18的分区的目录数据
                select * from student_ptn01; 全表扫描  查询所有的分区中的数据
                注意:进行查询的时候默认将最后一个查询的字段作为分区字段  多个分区字段一定是查询结果的最后几个字段  ,hive的1.2.2版本中  如果是多字段分区  必须指定至少一个分区为静态分区

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 'filepath'  select ...
      例: insert overwrite local directory '/home/hadoop/apps/hivedata' select * from stu_dynamic_ptn where department='IS';

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

2>导出数据到 HDFS

例:insert overwrite directory 'hdfs://hadoop02:9000/user/hive/warehouse/mystudent' select * from studentss;

2.4 Select 查询数据

Hive 中的 SELECT 基础语法和标准 SQL 语法基本一致,支持 WHERE、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]

讲一下四个 by :

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

2、 sort by(字段) 局部排序,不是全局排序,其在数据进入 reducer 前完成排序。因此,如 果用 sort by 进行排序,并且设置 mapred.reduce.tasks>1,则 sort by 只保证每个 reducer 的输出有序,不保证全局有序。 那万一,我要对我的所有处理结果进行一个综合排序,而且数据量又非常大,那么怎么 解决?我们不适用 order by 进行全数据排序,我们适用 sort by 对数据进行局部排序,完 了之后,再对所有的局部排序结果做一个归并排序

3、 distribute by(字段) 根据指定的字段将数据分到不同的 reducer,且分发算法是 hash 散列。 简单理解就是分组

4、 cluster by(字段) 除了具有 Distribute by 的功能外,还会对该字段进行排序。 因此,如果分桶和 sort 字段是同一个时,此时,cluster by = distribute by + sort by 如果我们要分桶的字段和要排序的字段不一样,那么我们就不能使用 clustered by

2.5 Hive Join查询

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

写查询时注意一下几点:

2.5.1、 只支持等值链接,支持 and,不支持 or

2.5.2、 可以 join 多于 2 个表(可参考2.5.3的实例)

例如: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。

2.5.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 表序列化。

2.5.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、 准备数据: 先准备两份数据,例如

tablea 表数据: 1,huangbo 2,xuzheng 4,wangbaoqiang 6,huangxiaoming 7,fengjie 10,liudehua

tableb 表的数据: 2,20 4,50 7,80 10,22 12,33 15,44

3、 分别导入数据到 tablea 表 和 tableb 表

4、 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_36508766/article/details/81320665
今日推荐