SQL ON Hadoop-Hive(二)-DDL数据定义语言

一.创建数据库

Hive中的数据库本质上仅仅是个表的目录或命名空间,在生产环境,如果表非常多,一般会用数据库将生产表组织成逻辑组。Hive中默认使用的数据库是default

数据库名+数据库所在的目录位置不能修改

--创建数据库(包含数据库键值对属性信息)
create database if not exists test
comment  'this is laotian'
with dbproperties('creator'='tianxiong','data'='2018-11-01') 
location '/files/tem/test.db';
show databases; --查看已存在的数据库

Hive会为每个创建的数据库在HDFS上创建一个目录,该数据库中的表会以子目录的形式存储,表中的数据会以表目录下文件形式存储

如果使用的是default数据库,该数据库没有自己的目录,数据库所在目录在hive-site.xml文件中配置项hive.metastore.warehouse.dir配置的目录之后,默认是在/user/hive/warehouse

hadoop fs -ls /user/hive/warehouse

在建表时修改默认的存储位置

create database if not exists test location '/user/hadoop/temp';

--查看某个已存在的数据库(数据库的描述+路径+键值对信息)
describe database [extended] test;  

use test		--切换当前工作的数据库

show tables	--显示该数据库中的表

drop database if exists test cascade;  --cascade表示删除数据库时,表中数据也一并删除,数据库删除后,其对应的HDFS目录也将会被一并删除

二.查看表信息

desc student --查看表列级别的注释信息,表结构信息

desc [extended/formatted] student --查看表的详细信息,会将表的信息输出至控制台

三.管理表+外部表

可以通过复制另外一张表的表结构(不复制数据)的方法来创建表

create table if not exists test.student1 like test.student location hdfs_path;

管理表:在hive中建表时,如果没有特别指明,都是hive中的管理表,意味着由hive负责管理表数据,默认会将数据保存到数据仓库目录下。当删除管理表时,hive将删除管理表中的数据和元数据

外部表(与管理表相对):当一份数据需要被多个工具分析时,如hive、pig。指这份数据的所有权并不由hive拥有,此时可以创建一个外部表指向这份数据

create external table if not exists test.student(
...
...
)
location '/user/test/x'
--当需要删除外部表时,hive认为没有完全拥有这份数据,故hive只会删除该外部表的元数据信息而不会删除该表的数据文件(依然在HDFS目录中)
--外部表在创建时,同时也会在默认路径下创建一个空目录

四.删除表

drop table if exists test;  --删除表
select 'user.*' from test;  --查询表中前缀为user的列

五.修改表

alter table子句修改表属性意味着仅仅修改表的元数据而不修改表本身的数据,故要保证表的数据和修改后的元数据模式匹配,否则数据不可用

a regexp b	--string类型,b是正则表达式
alter table table_name change column_name1 column_name1 <新数据类型>  --修改字段类型

--表重命名
alter table test rename to test2
--增加分区(通常是外部表)
alter table test add if not exists partition(x=x1,y=y1) location '/user/test/x1/y1' 
--修改已存在的分区路径
alter table test add partition(x=x1,y=y1) set location '/user/test/x1/y1'
--删除分区 
alter table test drop if exists partition (x=x1,y=y1)  

--对某个字段进行重命名,并修改数据类型/注释及表中的位置
alter table test change id uid int comment 'the unique id' after name 
--id字段重命名为uid并指定类型为int(即使类型和原来一样,也需重新指定)将该字段移动到name字段之后(移动到第一个位置使用first)

--增加一列或多列
alter table test add columns (new_col int,new_col2 string)
--删除test表中所有列,并重新定义列
alter table test replace columns (new_col int,new_col2 string) 

--内部与外部表转换
alter table table_name set tblproperties('EXTERNAL'='TRUE') 
alter table table_name set tblproperties('EXTERNAL'='FALSE')

--修改表存储属性
alter table table_name partiton(year=2011,month=1) set fileformat sequencefile;

六.join连接

1.多表join

select * from table1 t1 join table2 t2 on t1.id=t2.id join table3 t3 
on t1.id=t3.id    --第一个作业的输出与表3的连接操作
--目前hive只支持等值join,不支持非等值的连接(很难转化成map/reduce任务)可以join多于两个表,执行流程分析

--如果join多个表时,join key是同一个,则join会被转化为单个map/reduce任务,reducer端会缓存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.key1)

--如果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.key2)
--join被转化为2个map/reduce任务.因为b.key1用于第一次join条件,b.key2用于第二次join,第一次缓存a表用b表序列化,第二次缓存第一次map/reducer任务结果,然后用c表序列化

2.join时,每次map/reducer的任务逻辑

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

3.左半连接

hive特有语法,返回左表记录,前提是左表记录对于右边表满足on语句中的判定条件,被用来代替标准SQL中exists\in的操作(右表字段只能出现在on子句中,不能出现在select和where子句中引用,没有right semi join)

其实内连接也可以实现同样目的,但前者更高效(对于左表中的一条指定记录,在右表中一旦找到匹配记录,hive就停止扫描)

select t1.id from table_name t1 left semi join table_name2 t2 on t1.id=t2.id

4.join发生在where子句之前(以left/right outer join为例)

select a.val,b.val from a left outer join b on (a.key=b.key) where a.ds='2016-12-30' and b.ds='2016-12-30'
问题描述:如果b找不到对应a表的记录,所有列都会列出null包括ds列.也就是说join会过滤掉b表中不能找到匹配a表join key的所有记录,导致LEFT OUTER与where子句无关(是将left outer join后的结果进行where条件筛选)

解决方案:在left out时使用条件
select a.val,b.val from a left outer join b on (a.key=b.key and b.ds='2016-12-29' and a.ds='2016-12-29')
说明1:这一查询结果是预先在join阶段过滤的,所以不会存在上述的问题.这一逻辑可以用于right 和full类型的join中
说明2:过滤条件写在on上面会让基表所有数据都能显示,不满足条件的右表以null填充,当过滤条件写在where上只会让符合筛选条件的数据显示

--hive实例
select r.phone_num,r.lab1,s.phone_num,s.lab1 from  hkdw_dk_edu r left outer join hkdw_dk_edu s on (r.phone_num=s.phone_num and s.lab1='dk_seyy' and r.lab1='dk_sryyss') where r.lab1='dk_sryyss' and s.phone_num is null

5.内连接+全连接

--如果单独用join,如select ... from table_name1 a join table_name2 b on a.id=b.id表示内连接,full outer join全连接

6.map side join

如果在连接的表中,有一张是小表,在map阶段完全可以将小表读到内存中,直接在map端进行join,这种操作可以明显降低join所耗费的时间

select /*+MAPJOIN(t1)*/ t1.id,t2.id from table1 t1 join table2 t2 on t1.id=t2.id
--如果想让hive自动开启这个优化,设置hive.auto.convert.join=true(这样hive会在必要时自动执行map端join)

七.排序

order by与sort by语句:

order by-全局排序,必须由一个reducer来完成(不管有多少map,不管文件有多少block,只启动一个reducer),同时若指定hive.mapred.mode=strict,这时必须指定limit限定输出条数,原因是所有数据都在同一个reducer端进行,数据量大的情况下可能不能出结果

sort by-只会在每个reducer中进行局部排序

distribute by(控制map输出在reducer中是如何划分的)和sort by语句。distribute by可以自定义分发规则从而使得某些数据进入同一个reducer

select col1,col2 from table1 distribute by col1 sort by col1,col2
--保证col1相同的数据一定进入了同一reducer,在reducer中再按照col1,col2排序

cluster by(指定的列只能是降序)的功能是distribute by和sort by结合

--等价语句
select mid, money, name from store cluster by mid [sort by ...]
select mid, money, name from store distribute by mid sort by mid 

八.分桶

分桶(最大的作用是提高join操作效率,是更细颗粒度的数据范围划分)与抽样

1.hive提供对表的分桶抽样

select * from test tablesample(bucket 3 out of 10 on id);  
--10表示分成10个桶,3表示取第3个桶,id表示分桶的依据是将id列的哈希散列除以(10个桶)的余数(决定该条记录应该存放在哪个桶中),如果不指定id列,可以采用随机列抽样的方式
select * from test tablesample(bucket 3 out of 10 on rand())

2.分桶是为了性能考虑,可以理解为对分区内列进行再次划分,提高性能

在建表时指定分桶表--此时clustered by=distribute by

create table buckettable (id int,name string) partitioned by (clus string) clustered by (id) [sort by id [asc|desc]] into 4 buckets;
--该表被创建为4个桶,每个bucket对应一个目录
insert [into|overwrite] table buckettable select * from source --数据将被划分为4个文件存放在表路径下,每个文件代表一个桶
注:桶表数据必须从其他表转换
--修改参数允许强制分桶
hive>sethive.exec.mode.local.auto=true;
hive>set hive.enforce.bucketing=true;
hive>set mapreduce.job.reduces=6;		--reduce数量是分桶的数量个数

桶为表加上额外结构,hive在处理某些查询时能利用这个结构。join两个在相同列上划分了桶的表,可以使用map端连接进行高效实现map-side join,将保存相同列值的桶进行join操作即可,可大大减少join数据量

九.union all

hive不支持直接进行union all(必须具有相同的列+每个字段类型必须一致),必须进行嵌套查询
select t.id,t.name from
(select id,name from table1 union all select id,name from table2) t

 

你可能感兴趣的:(hive,Hadoop,hive,修改表,join连接,排序,分桶)