文章目录

  • Hive建表
  • 建表1:全部使用默认建表方式
  • 建表2:指定location (这种方式也比较常用)
  • 建表3:指定存储格式
  • 建表4:create table xxxx as select_statement(SQL语句) (这种方式比较常用)
  • 建表5:create table xxxx like table_name 只想建表,不需要加载数据
  • Hive加载数据
  • 1、使用```hdfs dfs -put '本地数据' 'hive表对应的HDFS目录下'```
  • 2、使用 load data inpath
  • 3、create table xxx as SQL语句
  • 4、insert into table xxxx SQL语句 (没有as)
  • Hive 内部表(Managed tables)vs 外部表(External tables)
  • 建表:
  • 加载数据:
  • 删除表:
  • Hive 分区
  • 建立分区表:
  • 增加一个分区:
  • 删除一个分区:
  • 查看某个表的所有分区
  • 往分区中插入数据:
  • 查询某个分区的数据:
  • Hive动态分区
  • 开启Hive的动态分区支持
  • 建立原始表并加载数据
  • 建立分区表并加载数据
  • 使用动态分区插入数据
  • 多级分区
  • Hive分桶
  • 开启分桶开关
  • 建立分桶表
  • 往分桶表中插入数据
  • HQL
  • 数据查询语言DQL
  • 数据操纵语言DML
  • 数据定义语言DDL
  • 数据控制语言DCL
  • HQL执行顺序
  • Hive With as 用法


Hive建表

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] 
   // 指定Hive储存格式:textFile、rcFile、SequenceFile 默认为:textFile
   [STORED AS file_format]
   
   | STORED BY 'storage.handler.class.name' [ WITH SERDEPROPERTIES (...) ]  (Note:  only available starting with 0.6.0)
  ]
  // 指定储存位置
  [LOCATION hdfs_path]
  // 跟外部表配合使用,比如:映射HBase表,然后可以使用HQL对hbase数据进行查询,当然速度比较慢
  [TBLPROPERTIES (property_name=property_value, ...)]  (Note:  only available starting with 0.6.0)
  [AS select_statement]  (Note: this feature is only available starting with 0.5.0.)
建表1:全部使用默认建表方式
create table students
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','; // 必选,指定列分隔符
建表2:指定location (这种方式也比较常用)
create table students2
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/input1'; // 指定Hive表的数据的存储位置,一般在数据已经上传到HDFS,想要直接使用,会指定Location,通常Locaion会跟外部表一起使用,内部表一般使用默认的location
建表3:指定存储格式
create table students3
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS rcfile; // 指定储存格式为rcfile,inputFormat:RCFileInputFormat,outputFormat:RCFileOutputFormat,如果不指定,默认为textfile,注意:除textfile以外,其他的存储格式的数据都不能直接加载,需要使用从表加载的方式。
建表4:create table xxxx as select_statement(SQL语句) (这种方式比较常用)
create table students4 as select * from students2;
建表5:create table xxxx like table_name 只想建表,不需要加载数据
create table students5 like students;

Hive加载数据

1、使用hdfs dfs -put '本地数据' 'hive表对应的HDFS目录下'
2、使用 load data inpath

下列命令需要在hive shell里执行

// 将HDFS上的/input1目录下面的数据 移动至 students表对应的HDFS目录下,注意是 移动、移动、移动
load data inpath '/input1/students.txt' into table students;
// 清空表
truncate table students;
// 加上 local 关键字 可以将Linux本地目录下的文件 上传到 hive表对应HDFS 目录下 原文件不会被删除
load data local inpath '/usr/local/soft/data/students.txt' into table students;
// overwrite 覆盖加载
load data local inpath '/usr/local/soft/data/students.txt' overwrite into table students;
3、create table xxx as SQL语句
4、insert into table xxxx SQL语句 (没有as)
// 将 students表的数据插入到students2 这是复制 不是移动 students表中的表中的数据不会丢失
insert into table students2 select * from students;

// 覆盖插入 把into 换成 overwrite
insert overwrite table students2 select * from students;

Hive 内部表(Managed tables)vs 外部表(External tables)

建表:
// 内部表
create table students_internal
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/input2';

// 外部表
create external table students_external
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/input3';
加载数据:
hive> dfs -mkdir /input2;
hive> dfs -mkdir /input3;
hive> dfs -put /usr/local/soft/data/students.txt /input2/;
hive> dfs -put /usr/local/soft/data/students.txt /input3/;
删除表:
hive> drop table students_internal;
Moved: 'hdfs://master:9000/input2' to trash at: hdfs://master:9000/user/root/.Trash/Current
OK
Time taken: 0.474 seconds
hive> drop table students_external;
OK
Time taken: 0.09 seconds
hive>

可以看出,删除内部表的时候,表中的数据(HDFS上的文件)会被同表的元数据一起删除,删除外部表的时候,只会删除表的元数据,不会删除表中的数据(HDFS上的文件).一般在公司中,使用外部表多一点,因为数据可以需要被多个程序使用,避免误删,通常外部表会结合location一起使用.外部表还可以将其他数据源中的数据 映射到 hive中,比如说:hbase,ElasticSearch…设计外部表的初衷就是让表的元数据与数据解耦.

Hive 分区

分区表实际上是在表的目录下在以分区命名,建子目录。
作用:进行分区裁剪,避免全表扫描,减少MapReduce处理的数据量,提高效率。
一般在公司的hive中,所有的表基本上都是分区表,通常按日期分区、地域分区。
分区表在使用的时候记得加上分区字段。
分区也不是越多越好,一般不超过3级,根据实际业务衡量。

建立分区表:
create table students_pt
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
PARTITIONED BY(pt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
增加一个分区:
alter table students_pt add partition(pt='20210622');
删除一个分区:
alter table students_pt drop partition(pt='20210112');
查看某个表的所有分区
show partitions students_pt; // 推荐这种方式(直接从元数据中获取分区信息)

select distinct pt from students_pt; // 不推荐
往分区中插入数据:
insert into table students_pt partition(pt='20210101') select * from students;
load data local inpath '/usr/local/soft/data/students.txt' into table students_pt partition(pt='20210111');
查询某个分区的数据:
// 全表扫描,不推荐,效率低
select count(*) from students_pt;

// 使用where条件进行分区裁剪,避免了全表扫描,效率高
select count(*) from students_pt where pt='20210101';

// 也可以在where条件中使用非等值判断
select count(*) from students_pt where pt<='20210112' and pt>='20210110';

Hive动态分区

有的时候我们原始表中的数据里面包含了 ‘‘日期字段 dt’’,我们需要根据dt中不同的日期,分为不同的分区,将原始表改造成分区表。hive默认不开启动态分区。

动态分区:根据数据中某几列的不同的取值划分不同的分区。

开启Hive的动态分区支持
# 表示开启动态分区
hive> set hive.exec.dynamic.partition=true;
# 表示动态分区模式:strict(需要配合静态分区一起使用)、nostrict
# strict: insert into table students_pt partition(dt='anhui',pt) select ......,pt from students;
hive> set hive.exec.dynamic.partition.mode=nostrict;
# 表示支持的最大的分区数量为1000,可以根据业务自己调整
hive> set hive.exec.max.dynamic.partitions.pernode=1000;
建立原始表并加载数据
create table students_dt
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string,
    dt string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
建立分区表并加载数据
create table students_dt_p
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
PARTITIONED BY(dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
使用动态分区插入数据
// 分区字段需要放在 select 的最后,如果有多个分区字段 同理,它是按位置匹配,不是按名字匹配
insert into table students_dt_p partition(dt) select id,name,age,gender,clazz,dt from students_dt;
// 比如下面这条语句会使用age作为分区字段,而不会使用student_dt中的dt作为分区字段
insert into table students_dt_p partition(dt) select id,name,age,gender,dt,age from students_dt;
多级分区
create table students_year_month
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string,
    year string,
    month string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

create table students_year_month_pt
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
PARTITIONED BY(year string,month string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

insert into table students_year_month_pt partition(year,month) select id,name,age,gender,clazz,year,month from students_year_month;

Hive分桶

分桶实际上是对文件(数据)的进一步切分,Hive默认关闭分桶。

作用:在往分桶表中插入数据的时候,会根据 clustered by 指定的字段 进行hash分组 对指定的buckets个数 进行取余,进而可以将数据分割成buckets个数个文件,以达到是数据均匀分布,方便我们取抽样数据,提高Map join效率。

分桶字段需要根据业务进行设定可以解决数据倾斜问题。

开启分桶开关
hive> set hive.enforce.bucketing=true;
建立分桶表
create table students_buks
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
CLUSTERED BY (clazz) into 12 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
往分桶表中插入数据
// 直接使用load data 并不能将数据打散
load data local inpath '/usr/local/soft/data/students.txt' into table students_buks;

// 需要使用下面这种方式插入数据,才能使分桶表真正发挥作用
insert into students_buks select * from students;

HQL

数据查询语言DQL
数据查询语言DQL基本结构是由SELECT子句,FROM子句,WHERE
子句组成的查询块:
SELECT <字段名表>
FROM <表或视图名>
WHERE <查询条件>
join:left join、right join、join     注意MapJoin

group by,order by,sort by,distribute by,cluster by的区别

group by : 通常结合聚合函数一起使用
order by:全局排序
sort by:局部排序
distribute by:分区
cluster by=distribuye by + sort by

count(*)、count(1) 、count(‘字段名’) 区别

count(*)和count(1)差别不大
count(*)将返回表格中所有存在的行的总数包括值为null的行
count(列名)将返回表格中除去null以外的所有行的总数(有默认值的列也会被计入)
数据操纵语言DML

数据操纵语言DML主要有三种形式:

1) 插入:INSERT
2) 更新:UPDATE
3) 删除:DELETE
数据定义语言DDL
数据定义语言DDL用来创建数据库中的各种对象-----表、视图、
索引、同义词、聚簇等如:
CREATE /DROP/ALTER  TABLE/VIEW/INDEX/SYN/CLUSTER
DDL操作是隐性提交的!不能rollback
数据控制语言DCL

数据控制语言DCL用来授予或回收访问数据库的某种特权,并控制
数据库操纵事务发生的时间及效果,对数据库实行监视等。如:

1) GRANT:授权。
2) ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。
回滚---ROLLBACK
回滚命令使数据库状态回到上次最后提交的状态。其格式为:
SQL>ROLLBACK;
3) COMMIT [WORK]:提交。
在数据库的插入、删除和修改操作时,只有当事务在提交到数据
库时才算完成。在事务提交前,只有操作数据库的这个人才能有权看
到所做的事情,别人只有在最后提交完成后才可以看到。
提交数据有三种类型:显式提交、隐式提交及自动提交。下面分
别说明这三种类型。
(1) 显式提交
用COMMIT命令直接完成的提交为显式提交。其格式为:
SQL>COMMIT;
(2) 隐式提交
用SQL命令间接完成的提交为隐式提交。这些命令是:
ALTER,AUDIT,COMMENT,CONNECT,CREATE,DISCONNECT,DROP,
EXIT,GRANT,NOAUDIT,QUIT,REVOKE,RENAME。
(3) 自动提交
若把AUTOCOMMIT设置为ON,则在插入、修改、删除语句执行后,
系统将自动进行提交,这就是自动提交。其格式为:
SQL>SET AUTOCOMMIT ON;
HQL执行顺序
from>where>group by>having>order by>join>select >limit
使用explain查看SQL执行计划,查看更加详细的执行计划,加上extended

where 条件里不支持不等式子查询,实际上是支持 in、not in、exists、not exists

例如: 列出薪金比“SMITH”多的所有员工。
错误示例

select * from emp where sal>(select sal from emp where ename='SMITH');

正确示例

select * 
from (select 1 as tmp_id,empno,ename,sal from emp where ename!='SMITH') t1
left join (select 1 as tmp_id,sal from emp where ename='SMITH')  t2
on t1.emp_id = t2.emp_id 
where t1.sal > t2.sal;

Hive With as 用法

// 之前的写法
select  t.id
        ,t.name
        ,t.clazz
        ,t.score_id
        ,t.score
        ,c.subject_name
from(
    select  a.id
        ,a.name
        ,a.clazz
        ,b.score_id
        ,b.score
    from (
        select  id
                ,name
                ,clazz
        from
        students
    ) a left join (
    select  id
            ,score_id
            ,score
    from score
    ) b
    on a.id = b.id
) t left join (
    select  subject_id
            ,subject_name 
    from subject
) c on t.score_id = c.subject_id
limit 10;

// with as 可以把子查询拿出来,让代码逻辑更加清晰,提高效率
// 必须跟着sql一起使用
with tmp1 as (
    select  id
            ,name
            ,clazz
    from students
), tmp2 as ( 
    select  score_id
            ,id
            ,score
    from
    score
), tmp1Jointmp2 as (
    select  a.id
            ,a.name
            ,a.clazz
            ,b.score_id
            ,b.score
    from tmp1 a
    left join tmp2 b
    on a.id = b.id
), tmp3 as (
select   subject_id
        ,subject_name 
from subject
)select  t.id
        ,t.name
        ,t.clazz
        ,t.score_id
        ,t.score
        ,c.subject_name
from tmp1Jointmp2 t left join tmp3 c
on t.score_id = c.subject_id
limit 10;