在工做中咱们常用的数据库,数据库通常存放的咱们系统中经常使用的数据,通常为百万级别。若是数据量庞大,达到千万级、亿级又须要对他们进行关联运算,该怎么办呢?
前面咱们已经介绍了HDFS和MapReduce了,它俩结合起来可以进行各类运算,但是MapReduce的学习成本过高了,若是有一种工具能够直接使用sql将hdfs中的数据查出来,并自动编写mapreduce进行运算,这就须要使用到咱们的hive数据仓库。java
Hive是基于Hadoop的一个数据仓库工具,能够将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。
用户接口:包括CLI、JDBC/ODBC、WebGUI
元数据存储:一般是存储在关系数据库如 mysql,derby中。
解释器、编译器、优化器、执行器
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只适合用来作批量数据统计分析。读多写少==node
db:在hdfs中表现为hive.metastore.warehouse.dir目录下的一个文件夹
table:在hdfs中表现为所属db目录下的一个文件夹
external table:与table相似,不过其数据存放位置能够在任意指定路径。删除表时只会删除元数据,不会删除实际数据
partition:在hdfs中表现为table目录下的子目录
bucket: 在hdfs中表现为同一个表目录下根据hash散列以后的多个文件
单机版(内置关系型数据库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 #添加以下内容 <configuration> <!--配置mysql的链接地址--> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true</value> <description>JDBC connect string for a JDBC metastore</description> </property> <!--配置mysql的驱动--> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> <description>Driver class name for a JDBC metastore</description> </property> <!--配置登陆用户名--> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> <description>username to use against metastore database</description> </property> <!--配置登陆密码--> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>root</value> <description>password to use against metastore database</description> </property> </configuration>
安装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中已在对应路径存在文件mysql
如今试试直接查询sql
==为了保证数据的安全,咱们通常把源数据表设置为外部表。数据只能经过外部加载导入==shell
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查询结果的几种方式:
一、将查询结果保存到一张新的hive表中
create table t_tmp as select * from t_p;
二、将查询结果保存到一张已经存在的hive表中
insert into table t_tmp select * from t_p;
三、将查询结果保存到指定的文件目录(能够是本地,也能够是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);
可见在hdfs上根据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采用对列值哈希,而后除以桶的个数求余的方式决定该条记录存放在哪一个桶当中。
好处: 一、方便抽样 二、提升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