在工作中我们经常使用的数据库,数据库一般存放的我们系统中常用的数据,一般为百万级别。如果数据量庞大,达到千万级、亿级又需要对他们进行关联运算,该怎么办呢?
前面我们已经介绍了HDFS和MapReduce了,它俩结合起来能够进行各种运算,可是MapReduce的学习成本太高了,如果有一种工具可以直接使用sql将hdfs中的数据查出来,并自动编写mapreduce进行运算,这就需要使用到我们的hive数据仓库。
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。
sequenceDiagram
客户端->>Hive处理转换成MapReduce: 发送HSQL语句
Hive处理转换成MapReduce->>MapReduce运行: 提交任务到Hadoop
MapReduce运行->>执行结果文件放到HDFS或本地: 执行结果
--- | Hive | RDBMS |
---|---|---|
查询语言 | HQL | SQL |
数据存储 | HDFS | Raw Device or Local FS |
执行 | MapReduce | Excutor |
执行延迟 | 高 | 低 |
处理数据规模 | 大 | 小 |
索引 | 0.8版本后加入位图索引 | 有复杂的索引 |
==hive中具有sql数据库,用来存储元数据信息(如:表的属性,数据的位置)。hive只适合用来做批量数据统计分析。读多写少==
单机版(内置关系型数据库derby)
元数据库mysql版
这里使用常用的mysql版,使用derby的话不太方便,因为derby会将文件保存在你当前启动的目录。如果下次你换个目录启动,会发现之前保存的数据不见了。
mysql安装仅供参考,不同版本mysql有各自的安装流程。
# 删除原有的mysql
rpm -qa | grep mysql
rpm -e mysql-libs-5.1.66-2.el6_3.i686 --nodeps
rpm -ivh MySQL-server-5.1.73-1.glibc23.i386.rpm
rpm -ivh MySQL-client-5.1.73-1.glibc23.i386.rpm
# 修改mysql的密码,并记得设置允许用户远程连接
/usr/bin/mysql_secure_installation
# 登录mysql
mysql -u root -p
vi conf/hive-env.sh
#配置其中的$hadoop_home
vi hive-site.xml
#添加如下内容
javax.jdo.option.ConnectionURL
jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true
JDBC connect string for a JDBC metastore
javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
Driver class name for a JDBC metastore
javax.jdo.option.ConnectionUserName
root
username to use against metastore database
javax.jdo.option.ConnectionPassword
root
password to use against metastore database
安装hive和mysql完成后,将mysql的连接jar包拷贝到$HIVE_HOME/lib目录下
如果出现没有权限的问题,在mysql授权
mysql -uroot -p
#执行下面的语句 *.*:表示所有库下的所有表 %:任何ip地址或主机都可以连接
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENDIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
到这一步其实已经安装好了,但是由于hadoop中的jline包版本和我们安装hive的jline包版本不一致,会导致hql无法被执行。
因此我们还要把hive的lib目录中的jline.2.12.jar替换掉$HADOOP_HOME/share/hadoop/yarn/lib/jline.0.9.94.jar
bin/hive
1.bin/hive
2.bin/beeline
!connect jdbc:hive2://server1:10000
3.bin/beeline -u jdbc:hive2://server1:10000 -n hadoop
create table tb_external(id int,name string) row format delimited fields terminated by',' location 'hdfs://kris/myhiveexternal';
在hdfs中已在对应路径存在文件
现在试试直接查询
==为了保证数据的安全,我们一般把源数据表设置为外部表。数据只能通过外部加载导入==
hive> create table student(id INT,age INT,name STRING)
> partitioned by(stat_date STRING)
> clustered by(id) sorted by(age) into 2 buckets
> row format delimited fields terminated by ',';
alter table student add partition(stat_date='20190613') partition(stat_date='20190614');
alter table student add partition(stat_date='20190615') location '/user/hive/warehouse/student';
alter table student drop partition(stat_date='20190613');
创建的分区会在hdfs对应的路径上创建文件夹
==如果增加的分区带了路径,那么不会在hdfs的路径上显示对应的文件夹==
show partitions student;
alter table student rename to students;
alter table students add columns(name1 string);
==增加的列会在所有列后面,在partition列前面==
alter table students replace columns(id int,age int,name string);
#查看表
show tables
#查看数据库
show databases
#查看分区
show partitions table_name
#查看方法
show functions
#显示表详细信息
desc extended table_name
#格式话表信息
desc formatted table_name
使用load data操作 hive会将文件复制到表对应的hdfs文件夹下
load data local inpath "students1.txt" [overwrite] into table students partition(stat_date="20190614");
加上overwrite会讲原有对应分区的数据清除。如果目标表(分区)已经有一个文件,并且文件名和filepath中的文件名冲突,那么现有的文件会被新文件所替代。
保存select查询结果的几种方式:
1、将查询结果保存到一张新的hive表中
create table t_tmp
as
select * from t_p;
2、将查询结果保存到一张已经存在的hive表中
insert into table t_tmp
select * from t_p;
3、将查询结果保存到指定的文件目录(可以是本地,也可以是hdfs)
insert overwrite local directory '/home/hadoop/test'
select * from t_p;
insert overwrite directory '/aaa/test'
select * from t_p;
插入分桶表的数据需要是已经分好桶的,创建分桶的表并不会自动帮我们进行分桶。
#设置变量,设置分桶为true, 设置reduce数量是分桶的数量个数
set mapreduce.job.reduces=2;
# 或者选择以下方式
set hive.enforce.bucketing = true;
# 向分桶表中插入数据
insert into student partition(stat_date='20190614')
select id,age,name from tmp_stu where stat_date='20190614' cluster by(id);
注意:==1.order by 会对输入做全局排序,因此只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。==
==2.sort by不是全局排序,它是在数据进去reduce task时有序。因此,如果用sort by进行排序,并且设置mapreduce.job.reduces>1,则sort by只保证每个reduce task的输出有序,不保证全局有序。==
==3.distribute by根据distribute by指定的内容将数据分到同一个reducer==
==4.cluster by除了具有distribute by的功能外,还会对该字段进行排序。因此我们可以这么认为cluster by=distribute by sort by==
==但是cluster by只能指定同一字段,当我们要对某一字段进行分桶,又要对另一字段进行排序时,用distribute by sort by更加灵活。==
==分桶表的作用:最大的作用是用来提高join操作的效率;==
思考:select a.id,a.name,b.addr from a join b on a.id=b.id;如果a表和b表已经是分桶表,而且分桶的字段是id字段。做这个join操作时,还需要全表做笛卡尔积吗?(文末给出答案)
数据分桶的原理:
跟MR中的HashPartitioner的原理一模一样
MR中:按照key的hash值去模除以reductTask的个数
Hive中:按照分桶字段的hash值去模除以分桶的个数
Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
好处:
1、方便抽样
2、提高join查询效率
将数据导入分桶表主要通过以下步骤
第一步:
从hdfs或本地磁盘中load数据,导入中间表(也就是上文用到的tmp_stu)
第二步:
通过从中间表查询的方式的完成数据导入
分桶的实质就是对 分桶的字段做了hash 然后存放到对应文件中,所以说如果原有数据没有按key hash ,需要在插入分桶的时候hash, 也就是说向分桶表中插入数据的时候必然要执行一次MAPREDUCE,这也就是分桶表的数据基本只能通过从结果集查询插入的方式进行导入
==我们需要确保reduce 的数量与表中的bucket 数量一致,为此有两种做法==
1.让hive强制分桶,自动按照分桶表的bucket 进行分桶。(推荐)
set hive.enforce.bucketing = true;
2.手动指定reduce数量
set mapreduce.job.reduces = num;
/
set mapreduce.reduce.tasks = num;
并在 SELECT 后增加CLUSTER BY 语句
觉得不错记得给我点赞加关注喔~
公众号:喜讯XiCent