当处理小数据集时,使用本地模式执行可以使Hive执行得更快些。
设置这个属性:
set hive.exec.model.local=true;
将会触发Hive更主动地使用这种模式,即使当前用户是在分布式模式或伪分布式模式下执行Hadoop的。
如果想默认使用这个配置,可以将这个属性加到配置文件中。(hive-site.xml)
vim $HIVE_HOME/.hiverc
set hive.cli.print.current.db=true;set hive.exec.model.local=true;
Hive使用环境变量 HADOOP_HOME 来指定Hadoop的所有相关JAR和配置文件。
$$HIVE_HOME/bin/hive 命令,这是个 bash shell脚本,用于启动CLI。
如果用户已经将 $HIVE_HOME/bin 加入到环境变量 PATH 中了,
那么只需要输入 hive 就可以执行命令了。$$HIVE_HOME/conf 目录下,
用户所做的配置修改只需要在 hive-site.xml 文件中进行就可以了。
如果这个文件(hive-site.xml)不存在,那么用户需要自己新建一个。Hive元数据储存配置(MySQL)
javax.jdo.option.ConnectionURL
javax.jdo.option.ConnectionDriverName
javax.jdo.option.ConnectionUserName
javax.jdo.option.ConnectionPasswordHive属性配置
<property>
 <name>hive.metastore.warehouse.dir</name>
 <value>/user/hive/warehouse</value>
</property
<property>
 <name>hive.exec.model.local</name>
 <value>true</value>
</property><property>
 <name>hive.metastore.uris</name>
 <value>thrift://centos02:9083</value>
 <description>默认端口9083</description>
</property>hive.metastore.warehouse.dir 这个属性默认值是:/user/hive/warehouse
当Hadoop配置的是分布式模式或伪分布式模式时,
这个路径被认为是分布式文件系统中的路径。元数据信息中存储了如:表的模式和分区信息...等元数据信息。
用户在执行如:create table xxx... 或 alter table xxx...等命令时会指定这些信息。
因为多用户和系统可能需要并发访问元数据存储,所以默认的内置数据库并不适用于生产环境。任何一个适用JDBC进行连接的数据库都可以作元数据储存。
大多数的Hive客户端会使用MySQL。
为了使Hive能够连接上MySQL,我们需要将JDBC驱动放置在类路径下。
这个驱动可以放置在Hive的库路径下,也就是 $HIVE_HOME/lib 目录下。
驱动和配置设置正确后,Hive就会将元数据信息存储到MySQL中。--config文件目录,这个命令允许用户覆盖 $HIVE_HOME/conf 中默认的属性配置
而指向一个新的配置文件目录。默认情况下,Hive不允许用户删除一个包含表的数据库。
用户要么先删除数据库中所有的表,然后再删除数据库。
要么在删除命令的后面加上关键字 cascade,这样可以使Hive自行先删除数据库中的表。drop database if exists vn009jj5 cascade ;
如果某个数据库被删除了,那么其对应的目录也同时会被删除。
列出表的tblproperties属性信息
show tblproperties wm_order_line ;如果表中的数据以及分区个数都非常大的话,
执行这样一个包含有所有分区的查询可能会触发一个巨大的MapReduce任务。
一个高度建议的安全措施就是将Hive设置为严格模式(strict),
这样如果对分区表进行查询而where子句没有加分区过滤的话,将会禁止提交这个任务。
set hive.mapred.model=strict;    --严格模式
set hive.mapred.model=nonstrict; --非严格模式 
删除表
drop table if exists wm_order_line;对于管理表,表的元数据信息和表内的数据都会被删除。
对于外部表,表的元数据信息会被删除,但是表中的数据不会被删除。 
Join语句
select
  a.store_id,b.store_name,
  a.div_id,c.div_name
from wm_order_line a
join store_info    b on b.store_id=a.store_id
join division_info c on c.div_id=a.div_id
;
大多数情况下,Hive会对每对Join连接对象启动一个MapReduce任务。
在本例中,首先会启动一个 MapReduce Job 对 表a 和 表b 进行连接操作,
然后会再启动一个 MapReduce Job 将第一个 MapReduce Job 的输出和 表c 进行连接操作。提示:
为什么不是 表b 和 表c 先进行连接操作呢?
这是因为Hive总是按照从左到右的顺序执行的。当对3个或者更多个表进行Join连接时,
如果每个 ON 子句都使用相同的连接键的话,那么只会产生一个 MapReduce Job。Hive同时假定查询中最后一个表是最大的那个表。
在对每行记录进行连接操作时,它会尝试将其他表缓存起来,然后扫描最后那个表进行计算。
因此,用户需要保证连接查询中的表的大小从左右到是依次增加的。幸运的是,用户并非总是要将最大的表放置在查询语句的最后面的。
这是因为Hive还提供了一个"标志"机制来显示地告知查询优化器哪张表是大表。select /*+ streamtable(a) */  --大表(wm_order_line a)
  a.store_id,b.store_name,
  a.div_id,c.div_name
from wm_order_line a
join store_info    b on b.store_id=a.store_id
join division_info c on c.div_id=a.div_id
;
现在Hive将会尝试将表wm_order_line作为驱动表,
即使它在查询中不是位于最后面的。还有另外一个类似的非常重要的优化叫做:map-side join。
map-side JOIN
如果所有表中只有一张表是小表,
那么可以在最大的表通过mapper的时候将小表完全放到内存中。
Hive可以在map端执行连接过程(称为:map-side join),
这是因为Hive可以和内存中的小表进行逐一匹配,从而省略掉常规连接操作所需要的Reduce过程。
即使对于很小的数据集,这个优化也明显地要快于常规的连接操作。
它不仅减少了Reducce过程,而且有时还可以同时减少Map过程的执行步骤。select /*+ mapjoin(b) */  --小表(store_info b)
  a.store_id,b.store_name,
  a.channel,a,order_id
from wm_order_line a
join store_info    b on b.store_id=a.store_id从 Hive 0.7 版本开始,废弃了这种标记的方式,
不过,如果增加了这个标记同样是有效的。
如果不加这个标志,那么用户需要设置属性:hive.auto.convert.join 的值为 true,
这样Hive才会在必要的时候启动这个优化。
默认情况下这个属性的值是:false。set hive.auto.convert.join=true;
用户也可以配置能够使用这个优化的小表的大小(单位是:字节 Bytes)。
set hive.mapjoin.smalltable.filesize=25000000 ; --23.84MB
 
Distribute By
Distribute By 控制 map的输出在 Reduce中是如何划分的。
MapReduce Job 中传输的所有数据都是按照 键-值对的方式进行组织的,
因此Hive在将用户的查询语句转换成 MapReduce Job时,它必须在内部使用这个功能。默认情况下,MapReduce计算框架会依据 map输入的键计算相应的哈希值,
然后按照得到的哈希值将键-值对均匀分发到多个Reduce中去。可以使用 Distribute By 来保证具有相同 order_id 的记录分发到同一个Reduce中进行处理。
select 
  a.store_id, a.channel,a,order_id
from wm_order_line a 
Distribute By a.order_id
;select 
  a.store_id, a.channel,a,order_id
from wm_order_line a 
Cluster By a.order_id
;索引
Hive只有有限的索引功能。Hive中没有关系型数据库中键的概念,
但是还是可以对一些字段建立索引来加速某些操作的。
一张表的索引数据存储在另一张表中。建立索引可以帮助裁剪掉一张表的一些数据块,这样能够减少MapReduce的输入数据量。
并非所有的查询都可以通过建立索引获得好处,
通过 explain 命令可以查看某个查询语句是否用到了索引。Hive中的索引和关系型数据库中的一样,需要进行仔细评估才能使用。
维护索引也需要额外的存储空间,同时创建索引也需要消耗计算资源。
用户需要在建立索引为查询带来的好处 和 因此而需要付出的代价之间做出权衡。create index inx_order_orderId --索引名称
on table wm_order_line (order_id)
as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
with deferred rebuild
in table order_index_table --索引放在另一张新表里
partitioned by (channel,paid_date)
;show formatted index   on wm_order_line ; --显示索引
show formatted indexes on wm_order_line ; --显示索引(列举出多个索引信息)--删除索引
drop index if exists inx_order_orderId
on table wm_order_line ;如果被索引的表被删除了,那么它对应的索引和索引表也会被删除。
同样地,如果原始表的某个分区被删除了,那么这个分区对应的分区索引也同时会被删除掉。关于分区
HDFS用于设计存储数百万的大文件,而非数十亿的小文件。
使用过多分区可能导致的一个问题就是会创建大量的非必要的Hadoop文件和文件夹。
一个分区就对应着一个包含有多个文件的文件夹。
如果指定的表存在数百个分区,那么可能每天都会创建好几万个文件。
如果保持这样的表很多年,那么最终就会超出"NameNode"对系统元数据信息的处理能力。
因为NameNode必须要将所有的系统文件的元数据信息保存在内存中。
虽然每个文件只需要少量字节大小的元数据(大约是150字节/文件),
但是这样也会限制一个HDFS实例所能管理的文件总数的上限。MapReduce会将一个作业(Job)转换成多个任务(task)。
默认情况下,每个task都是一个新的JVM实例,都需要开启和销毁的开销。
对于小文件,每个文件都会对应一个task。
在一些情况下,JVM开启和销毁的时间中,销毁可能会比实际处理数据的时间消耗要长。
因此,一个理想的分区方案不应该导致产生太多的分区和文件夹目录,
并且每个目录下文件应该足够得大,应该是文件系统中块大小的若干倍。分桶表数据存储
分区提供一个隔离数据和优化查询的便利的方式。不过,并非所有的数据集都可以形成合理的分区。分桶是将数据集分解成更容易管理的若干部分的另一个技术。
如果对表进行分桶,并使用 order_id 字段作为分桶字段,则字段值会根据用户指定的值进行哈希分发到桶中。
同一个 order_id 下的记录通常会存储到同一个同内。create table wm_order_line
(
  store_id   int,
  order_id  string,
  gmv       decimal(10,2)
)
partitioned by (channel string, paid_date date)
clustered by order_id into 10 buckets
;set hive.enforce.bucketing=true;
如果没有使用 hive.enforce.bucketing 属性,
那么就需要自己设置和分桶个数相匹配的 reduce个数。例如,使用 set mapred.reduce.task=10,
然后在 insert 语句中,需要在 select语句后增加 clustered by语句。分桶有几个优点。
因为桶的数量是固定的,所以它没有数据波动。
分桶同时有利于执行高效的 map-side join 。使用压缩
压缩可以使磁盘上存储的数据量变小,这样可以通过降低I/O来提高查询执行速度。
Hive可以无缝地使用很多压缩类型。
但是,压缩和解压都会消耗CPU资源。
MapReduce任务往往是I/O密集型的,因此CPU开销通常不是问题。
不过,对于工作流这样的CPU密集型的场景,
例如:一些机器学习算法,压缩实际上可能会从更多必要的操作中获取宝贵的CPU资源,从而降低性能。调优
一个Hive任务会包含有一个或多个阶段(stage),不同的阶段(stage)间会存在着依赖关系。
越复杂的查询通常将会引入越多的stage,而通常stage越多就需要越多的时间来完成任务。一个stage可以是一个MapReduce任务
默认情况下,Hive会一次只执行一个阶段(stage)。explain  select sum(gmv) from wm_order_line;
explain extended  select sum(gmv) from wm_order_line;使用 explain extended 语句可以产生更多的输出信息。
Join 优化
要清楚哪个表是最大的,并将最大的表放置在 join语句的最右边,或直接使用 /* streamtable(table_name) */ 语句指出。如果所有表中有一个表足够得小,是可以完成载入到内存中的,
那么这时Hive可以执行一个 map-side join,这样可以减少reduce过程,
有时甚至可以减少某些 map task 任务。
有时候即使某些表不适合载入内存也可以使用 map-side join,
因为减少reduce阶段可能比将不太大的表分发到每个 map task 中会带来更多的好处。本地模式
有时Hive的输入数据量是非常小的。
在这种情况下,为查询触发执行任务的时间消耗可能会比实际Job的执行时间要多得多。
对于大多数这种情况,Hive可以通过本地模式在单台机器上(或某些时候在单个进程中)处理所有的任务。
对于小数据集,执行时间可以明显被缩短。--在执行过程中临时启用本地模式
set mapred.job.tracker=local;用户可以通过设置属性
set hive.exec.model.local.auto=true
来让Hive在适当的时候自动启动这个优化。
如果希望对所有的用户都使用这个配置,可以将这个配置增加到 $HIVE_HOME/conf/hive-site.xml
<property>
 <name>hive.exec.model.local</name>
 <value>true</value>
</property>并行执行
Hive会将一个查询转化成一个或者多个阶段。
默认情况下,Hive一次只会执行一个阶段。
不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,
也就是说,有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。
不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。set hive.exec.parallel=true;
通过以上设置就可以开启并发执行。
不过,在共享集群中,需要注意下,如果job中并行执行的阶段增多,那么集群利用率就会增加。JVM重用
Hadoop的默认配置通常是使用派生JVM来执行 map和reduce 任务的。
这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千个task任务的情况。
JVM重用可以使得JVM实例在同一个job中重新使用n次。
n的值可以在Hadoop的 mapred-site.xml 中进行设置。($HADOOP_HOME/conf/mapred-site.xml)这个功能的一个缺点是:
开启JVM重用将会一直占用使用到的task插槽,以便进行重用,直到任务完成才能释放。单个MapReduce中多个 Group By 
将查询中多个 group by  操作组装到单个 MapReduce任务中。
set hive.multigroupby.singlemr=false; 
其他文件格式和压缩方法
压缩通常都会节约可观的磁盘空间,压缩同样可以增加吞吐和性能。
压缩和解压会增加额外的CPU开销,
不过,通过减少载入内存的数据量而提高I/O吞吐量会更加提高网络传输的性能。Hadoop的job通常是I/O密集型的而不是CPU密集型的。
如果是这样的话,压缩可以提高性能。
不过,如果用户的job是CPU密集型的话,那么使用压缩可能会降低执行性能。
确定是否进行压缩的唯一方法就是尝试不同的选择,并测量对比执行结果。Hive中可以通过 set命令查看Hive配置文件中或Hadoop配置文件中配置的值。
hive -e "set io.compression.codecs" 使用压缩的优势是可以最小化所需要的磁盘存储空间,以及减少磁盘和网络I/O操作。
不过,文件压缩过程和解压过程会增加CPU开销。为什么我们需要不同的压缩方案呢?
每一个压缩方案都在压缩/解压缩的速度和压缩率间进行权衡。
BZip2压缩率最高,但是同时需要消耗最多的CPU开销。
GZip是"压缩率"和"压缩/解压缩"速度上的下一个选择。
因此,如果磁盘空间利用率和I/O开销都需要考虑的话,那么这两种方案都是有吸引力的。LZO和Snappy压缩率相比BZip2和GZip要小,
但是,压缩/解压缩速度要快,特别是解压缩过程。
如果相对于磁盘空间和I/O开销,频繁读取数据所需的解压缩速度更重要的话,那么它们将是不错的选择。另一个需要考虑的因素是:压缩格式的文件是否是可分割的(分片)。
MapReduce需要将非常大的输入文件分割成多个划分(通常一个文件块对应一个划分,也就是128MB的倍数),
其中每个划分会被分发到一个单独的map进程中。
只有当Hadoop知道文件中记录的边界时才可以进行这样的分割。
BZip2和LZO提供了块(block)级别的压缩,也就是每个块中都含有完整的记录信息。所有的这些信息用户在创建表的时候都可以在表定义语句中进行指定。
创建完成后,用户可以像平时一样查询表,而无需关心底层格式。开启中间压缩
对中间数据进行压缩可以减少job中map和reduce task间的数据传输量。
对于中间数据压缩,选择一个低CPU开销的编/解码器要比选择一个压缩率高的编/解码器要重要得多。
属性:hive.exec.compress.intermediate 的默认值是 false。
如果要开启中间压缩就需要将这个属性值修改为:true。set hive.exec.compress.intermediate=true;
或
<property>
 <name>hive.exec.compress.intermediate</name>
 <value>true</value>
</property>对于其他Hadoop job 来说,控制中间数据压缩的属性是:mapred.compress.map.output 
Hadoop压缩默认值的编/解码器是:DefaultCodec。
可以通过修改属性:mapred.map.output.compression.codec 的值来修改编/解码器。
这是一个Hadoop配置项,可以在 $HADOOP_HOME/conf/mapred-site.xml 或 hive-site.xml 文件中进行配置。
SnappyCodec是一个比较好的中间文件压缩编/解码器,因为它很好地结合了低CPU开销和好的压缩执行效率。set mapred.map.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
或
<property>
 <name>mapred.map.output.compression.codec</name>
 <value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>最终输出结果压缩
当Hive将输出写入到表中时,输出内容同样可以进行压缩。
属性:hive.exec.compress.output 控制着这个功能。
用户可能需要保持默认配置文件中的默认值 false,这样默认的输出就是非压缩的纯文本文件了。
用户可以通过在查询语句或执行脚本中设置这个值为:true,来开启输出结果压缩功能。set hive.exec.compress.output=true;
或
<property>
 <name>hive.exec.compress.output</name>
 <value>true</value>
</property>对于其他 Hadoop任务,开启最终输出结果压缩功能的属性是:mapred.output.compress
如果属性:hive.exec.compress.output 的值为 ture,那么这时需要为它指定一个编解码器。
对于输出文件,使用GZip进行压缩是个不错的主意,因为它通常可以大幅度降低文件的大小。
但是,需要记住的是,GZip压缩的文件对于后面的 MapReduce job 而言是不可分割的。set mapred.output.compression.codec=org.apache.hadoop.io.compress.GZipCodec;
或
<property>
 <name>mapred.output.compression.codec</name>
 <value>org.apache.hadoop.io.compress.GZipCodec</value>
</property>