hive中的表与hdfs中的文件通过metastore关联起来的.
Hive的数据模型:内部表,分区表,外部表,桶表
受控表(managed table):包括内部表,分区表,桶表
内部表:
我们删除表的时候在hdfs上对应的目录及数据文件一同被删除了.
分区表:
分区:把数据放在不同的磁盘文件中,就认为是不同的分区,数据库对不同的分区会进行单独的管理,优化,最终的目的是加快我们数据查询的速度,在hive中,把不同的分区分在表中不同的子文件夹中.
分区字段就是一个文件夹的标示.和内部表的区别在于分区.
create table jiuye(id int,name string) partitioned by (grade int) row format delimited fields terminated by ' '; load data local inpath './user' into table jiuye partition(grade='1'); load data local inpath './user' into table jiuye partition(grade=2); load data local inpath './user' into table jiuye partition(grade=3); select * from jiuye where grade=3; create table member(id int,name string) partitioned by (year int,month int) row format delmited fields terminated by ' '; load data local inpath './user' into table member partition(year=2014,month=1); load data local inpath './user' into table member partition(year=2014,month=2);
分区不是越多越好,如果把分区分的特别多的话,意味着在加载数据的时候要注意这个文件必须是符合特定分区的,这个文件会被控制的特别小.
如果文件特别小,分区特别多的时候,hive在进行扫描的时候也会特别麻烦.
分区越多就会产生大量的小文件,小文件的缺点就是hdfs在运行的时候就会造成map的数量增多,对整体的运算效率不见得是好事.
hive不允许无限制的创建分区,限定了分区的数量.
选用一些平时查询比较频繁的字段,并且不会有很多枚举值的字段,适合作为分区字段.
在正常使用的时候分区字段是作为正常的字段被使用的.但是在我们的数据文件中是不存在的,所以这个分区字段是作为虚拟列(virtual column)存在的.
桶表(bucket table):
原理:
分区表是按照经常查询的字段做不同的分区,查询时就可以按分区进行查了.这样可以减小全局扫描提高查询的速度.分区表的缺陷就是选定了分区字段之后,结果会造成数据偏差特别大,有的分区数据特别大,有的分区数据特别小,这个时候作业的整个查询时间就受制于分区中数据特别大的那个分区,对整个作业的运行效率是不好的.
桶表和分区表的区别在于:不是按照业务字段来进行分区,对里面的记录做一个hash,记录做完hash之后就没有规律了,可以简单的认为数据做完hash之后都不相同,然后我们让数据进行模10,数据就被分成了十份,模100就被分成100份,因为hash值几乎各不相同,所以模后的结果,分成10份或者100份,每一份的数据量几乎是一样多的,当你hash之后然后模一个数字,分的那些数据量,每一份应该是差不多的,如果这样的话,我们把这样的数据存起来,模5,10,100 模的这个数字叫做桶,模几就分成几个桶,桶实际上就是模的数字,我们的记录就被划分到这个桶里面了,那么hive在进行查询的时候就会按照5个桶或者10个桶来进行处理,这样的话,好处是各个map运行的时间差不多.
桶表用的领域很少,一般用在表连接中,有两个表,有一个外键是连接字段,我们的这一个表里面的字段和另外一个的连接字段的值是相同的,hash后的值应该也相同,分桶的话会分到相同的桶中,在进行表连接的时候就比较方便了,只需要把对应的桶的数据连接一下然后再从里边查数据就方便了.
还有一个优点就是在进行抽样查询的时候,我们的记录只有10亿条记录,要查一下北京的有多少个,没必要把十亿条记录全扫一遍,但是可以扫一万或者一百万看一下北京的有多少,然后就可以大体的判断一下北京的大约占多少百分比了.抽样不需要一个准确的值,只需要一个样本就可以了,这样样本只要符合统计学上的大小就可以了,那么我们在进行抽样的话,如果按照桶表来进行抽样更合理,如果按时间抽,统计结果就不准了.
创建桶表:
create table bucket_table(id int,name string) clustered by(id) into 3 buckets;
加载数据:
需要计算id的hash值,分桶.所以不能使用load data,load data加载方式是直接把数据从我们的磁盘复制到hdfs目录下,但是我们的分桶需要计算,计算需要走mapreduce,所以需要通过这种方式走mapreduce
设置启用桶 set hive.enforce.bucketing=true; insert overwrite table bucket_table select id,name from jiuye;
分桶之后是三个文件,分区表是文件夹.桶表和分区表目的都是为了把数据进行划分,只是划分的方式不一样,一个是从业务字段的角度来划分,一个是抛弃了业务字段从纯数据的角度来进行划分,纯数据的角度和查询就不搭界了,主要就是用于抽样,表连接.
外部表:
受控表在删除一个表的时候,会把hdfs中的目录给删除掉,外部表是你在删除这个表的时候只删除了表定义,对于hdfs中的这些数据等等不会做删除.外部表在hive对应的数据库中是没有记录的,不对应hdfs中的文件夹,但可以在mysql中找到select * from tbls;
灵活,可以随便定义表结构.工作中外部表和分区表使用的比较多.
create external table ext_table(c1 string,c2 string) row format delimited fields terminated by ' ' location '/fiels'; select * from ext_table; select c1 from ext_table; drop table ext_table;
hive的存储:
hadoop的存储形式有数据库,文件,表,视图,索引.
hive把数据加载进来之后是存储在hdfs中的,对数据的存储格式也有不同,最常见的就是TextFile,SequenceFile,RCFile,仅用于数据存储.
TextFile:把文件原封不动的上传到hdfs中,可以很方便的查看文件的内容.
SequenceFile:hadoop特有的一种数据存储格式,特点是支持压缩.这样数据的体积就会少.
RCFile:列式存储,我们平时在存储文件的时候都是按行一行一行的存储,关系数据库mysql,oracle都是行式存储.
优点就是可以减少数据的体积.行存储,简单的说就是一个稀疏矩阵,二维表可以看做是一个稀疏矩阵,稀疏矩阵它有很多表都是空的,空的在按行进行存储的时候一个都不能少,列式存储就可以省略这些元素,不存储减少这些空间,
还有一个好处是查询速度快,行式存储在查询的时候一行一行的都走,然后加载到内存来处理,列式存储是按列存的,因此在查询的时候就可以把需要的列给读走,加载到内存来查询.如果select * 查询,那么行式存储和列式存储就没有区别了.
set命令:显示修改变量.
命令行操作:
hivevar:hive --define name=zhangsan; hiveconf:hive --hiveconf hive.cli.print.current.db=true;hive在显示的时候显示当前的数据库.通常用来修改配置中的值 hive --hiveconf hive.cli.print.header=true;在显示数据的时候可以把列的名称给显示出来. system:读取java定义的变量值,system:user.name env:shell环境变量,env:user
测试:
hive --hiveconf hive.cli.print.current.db=true; create database mydb; use mydb;可以很方便的看到数据库名称,在有很多的数据库的时候有用. quit; hive --hiveconfig hive.cli.print.header=true; show tables ; select * from jiuye; quit; /** 有问题 today=`date +'%Y_%m_%d'`; echo $today; hive; create table log_${env:today}{id int}; */
~/.hiverc:hive在进行初始化的时候会先去执行,可以放一些hive初始化的值
~/.hivehistory:记录hive执行过的所有的命令
cd ~; ls -a; vi .hiverc; set hive.cli.print.current.db=true; set hive.cli.print.header=true; set hive.querylog.location=/usr/local/hive/logs; 忘记设置的值可以使用set命令再次查看一次. hive; select * from jiuye; set hive.cli.print.current.db;
hive -e "命令":在不进入hive命令行,shell命令下直接执行hive命令.
hive -e "select * from jiuye"; hive -e "" >> aaa:hive执行的结果保存到aaa中.好处:程序执行一次不可能我们只是看一看结果,有可能我们去执行很多的内容,也有可能让hive执行的结果保存到aaa中,然后aaa又作为另一个程序的输入的数据,这样的话就需要把hive执行的结果保存到一个文件中,这样就把hive中的数据给抽取出来了,供给别的程序使用了. hive -e "select * from jiuye" >> aaa; ls ; more aaa; hive -S -e vi "命令">>bbb和hive -e "命令">>aaa的区别:运行的时候可以更安静的去执行. hive --hiveconf hive.querylog.location=/usr/local/hive/logs:修改hive输出的路径,执行时指定,可以放到~/hiverc中 hive -f file:写了很多的hive脚本放到一个文件中的时候可以使用hive -f file去执行 source file: hive命令行下,想执行的那些脚本写在一个文件中,去执行文件中的那些脚本使用source file;