1、运行模式(本地模式/集群模式)
1.job的输入数据大小必须小于参数:hive.exec.mode.local.auto.inputbytes.max(默认128MB)
2.job的map数必须小于参数:hive.exec.mode.local.auto.tasks.max(默认4)。而Map task个数是有default_num = total_size / block_size计算得出
;
3.job的reduce数必须为0或者1
可用参数hive.mapred.local.mem(默认0)控制child jvm使用的最大内存数。
本地模式下需要注意设置 mapred.local.dir 本地目录,并且赋予执行用户权限。不然会出现No space available in any of the local directories 异常。
使用场景:
有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化。
这边对如下数据做测试,总的数据大小为161B:
查询语句:select salary,count(*) from employee group by salary;
集群模式下:
本地模式下:
从上面执行的结果可以看出,执行时间明显的缩短。
2、计算引擎 (MR/TEZ/SPARK)
hive默认引擎是mr,执行job时可以看到上面日志,HIVE2后已经建议使用tez/spark计算引擎。
hive 的引擎设置 hive.execution.engine
下列对 数据量为 14401261 条,大小为2.8G的 textfile格式的数据进行测试。
测试执行语句:
select cs_sold_date_sk,count(*) from catalog_sales group by cs_sold_date_sk;
MR:
set hive.execution.engine=mr;
测试的平均值在38秒左右
TEZ:
set hive.execution.engine=tez;
对比MR,TEZ的优化技术:
产生一个Mapreduce任务就提交,影响任务的效率,Tez的优化策略是创建一个ApplicationMaster的缓存池,作业提交到AMppplserver中,预先启动若干ApplicationMaster形成AM缓冲池。
同时ApplicationMaster启动的时候也可以预先启动几个container,做为容器的缓冲池。
此外ApplicationMaster运行完成后,不会马上注销其下的container,而是将其预先分配给正要运行的任务。
Tez的好处就是避免产生较多的Mapreduce任务,产生不必要的网络和磁盘IO.
下图是运行完后保留的ApplicationMaster。
测试分三种情况如果执行完上一次,立即再次执行平均只需要7秒左右。如果等container资源释放后再执行则平均需要13秒,等applicationMaster结束再执行的话需要17秒。
SPARK:
set hive.execution.engine=spark;
除了第一次连接过程需要较长的时间20s,后续的执行平均只需要6秒完成。
以下是spark的运行情况
hive 使用 spark引擎 部署配置遇到问题可以查看 Hive on Spark
3、文件存储格式
Hive中常用文件存储格式有
- TextFile 行存储 默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
- Parquet 列存储 最初的设计动机是存储嵌套式数据,比如Protocolbuffer,thrift,json等,将这类数据存储成列式格式,以方便对其高效压缩和编码,且使用更少的IO操作取出需要的数据,这也是Parquet相比于ORC的优势,它能够透明地将Protobuf和thrift类型的数据进行列式存储。不支持update操作(数据写成后不可修改)。
- ORC 列式存储 默认zlib压缩 ORC是在一定程度上扩展了RCFile,是对RCFile的优化。ORC是列式存储,有多种文件压缩方式,并且有着很高的压缩比。文件是可切分(Split)的。因此,在Hive中使用ORC作为表的文件存储格式,不仅节省HDFS存储资源,查询任务的输入数据量减少,使用的MapTask也就减少了。提供了多种索引,row group index、bloom filter index。ORC可以支持复杂的数据结构(比如Map等)
- Sequence 行存储 二进制文件,以<key,value>的形式序列化到文件中,SequenceFile是Hadoop API提供的一种二进制文件支持,其具有使用方便、可分割、可压缩的特点。SequenceFile支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。
- RC RCFile 列存储 文件格式是FaceBook开源的一种Hive的文件存储格式,首先将表分为几个行组,对每个行组内的数据进行按列存储,每一列的数据都是分开存储,正是先水平划分,再垂直划分的理念。
- AVRO 行式存储 一种远程过程调用和数据序列化框架,是在Apache的Hadoop项目之内开发的。它使用JSON来定义数据类型和通讯协议,可以在Hadoop生态系统和以任何编程语言编写的程序之间交换数据,使用压缩二进制格式来序列化数据。
下面对以上存储格式进行存储空间和SQL查询两个方面的比较.
采用MR计算引擎,执行三次以上平局值。以14401261 条,大小为2.8G的 textfile格式的数据作为源表。
文件存储格式 | HDFS存储空间 | 不含group by select count(*) from table | 含group by select cs_sold_date_sk,count(*) from table group by cs_sold_date_sk limit 1; |
---|---|---|---|
TextFile | 2.8G | 46s | 84s |
Parquet | 1.2G | 22s | 36s |
ORC | 711.8 M | 12s | 19.3s |
Sequence | 3.0 G | 182s | 222s |
RC | 1.8 G | 40s | 66s |
AVRO | 1.8G | 265s | 290s |
从上面的测试结果可以看出
- 从占用存储空间来看,ORC和Parquet文件格式占用的空间相对而言要小得多。
- 从执行SQL效率来看,ORC和Parquet文件格式查询耗时要相对而言要小得多。
从目前所得的结论来看,Hive中选用ORC和Parquet文件格式似乎更好一点,但是Hive默认的文件存储格式是TextFile,这是因为大多数情况下源数据文件都是以text文件格式保存(便于查看验数和防止乱码),这样TextFile文件格式的Hive表能直接load data数据。
如果说我们想使用ORC文件或者Parquet文件格式的表数据,可以先通过TextFile表加载后再insert到指定文件存储格式的表中。而这些不同文件格式的表我们可以通过数据分层保存,便于后期进行数据统计。
对于ORC和Parquet的选择,从上面的结论ORC比Parquet要好。但是由于ORC的一些局限性,比如Impala不支持orc,实际生产中使用Parquet比较多。
Hive数仓建表该选用ORC还是Parquet,压缩选LZO还是Snappy?
TextFile
select count(*) from catalog_sales;
select cs_sold_date_sk,count(*) from catalog_sales group by cs_sold_date_sk limit 1;
Parquet
CREATE EXTERNAL TABLE `catalog_sales_parquet`( `cs_sold_date_sk` bigint, `cs_sold_time_sk` bigint, `cs_ship_date_sk` bigint, `cs_bill_customer_sk` bigint, `cs_bill_cdemo_sk` bigint, `cs_bill_hdemo_sk` bigint, `cs_bill_addr_sk` bigint, `cs_ship_customer_sk` bigint, `cs_ship_cdemo_sk` bigint, `cs_ship_hdemo_sk` bigint, `cs_ship_addr_sk` bigint, `cs_call_center_sk` bigint, `cs_catalog_page_sk` bigint, `cs_ship_mode_sk` bigint, `cs_warehouse_sk` bigint, `cs_item_sk` bigint, `cs_promo_sk` bigint, `cs_order_number` bigint, `cs_quantity` int, `cs_wholesale_cost` decimal(7,2), `cs_list_price` decimal(7,2), `cs_sales_price` decimal(7,2), `cs_ext_discount_amt` decimal(7,2), `cs_ext_sales_price` decimal(7,2), `cs_ext_wholesale_cost` decimal(7,2), `cs_ext_list_price` decimal(7,2), `cs_ext_tax` decimal(7,2), `cs_coupon_amt` decimal(7,2), `cs_ext_ship_cost` decimal(7,2), `cs_net_paid` decimal(7,2), `cs_net_paid_inc_tax` decimal(7,2), `cs_net_paid_inc_ship` decimal(7,2), `cs_net_paid_inc_ship_tax` decimal(7,2), `cs_net_profit` decimal(7,2)) ROW format delimited fields terminated by '|' stored as parquet;
insert overwrite table catalog_sales_parquet select * from catalog_sales;
select count(*) from catalog_sales_parquet;
select cs_sold_date_sk,count(*) from catalog_sales_parquet group by cs_sold_date_sk limit 1;
ORC
CREATE EXTERNAL TABLE `catalog_sales_orc`( `cs_sold_date_sk` bigint, `cs_sold_time_sk` bigint, `cs_ship_date_sk` bigint, `cs_bill_customer_sk` bigint, `cs_bill_cdemo_sk` bigint, `cs_bill_hdemo_sk` bigint, `cs_bill_addr_sk` bigint, `cs_ship_customer_sk` bigint, `cs_ship_cdemo_sk` bigint, `cs_ship_hdemo_sk` bigint, `cs_ship_addr_sk` bigint, `cs_call_center_sk` bigint, `cs_catalog_page_sk` bigint, `cs_ship_mode_sk` bigint, `cs_warehouse_sk` bigint, `cs_item_sk` bigint, `cs_promo_sk` bigint, `cs_order_number` bigint, `cs_quantity` int, `cs_wholesale_cost` decimal(7,2), `cs_list_price` decimal(7,2), `cs_sales_price` decimal(7,2), `cs_ext_discount_amt` decimal(7,2), `cs_ext_sales_price` decimal(7,2), `cs_ext_wholesale_cost` decimal(7,2), `cs_ext_list_price` decimal(7,2), `cs_ext_tax` decimal(7,2), `cs_coupon_amt` decimal(7,2), `cs_ext_ship_cost` decimal(7,2), `cs_net_paid` decimal(7,2), `cs_net_paid_inc_tax` decimal(7,2), `cs_net_paid_inc_ship` decimal(7,2), `cs_net_paid_inc_ship_tax` decimal(7,2), `cs_net_profit` decimal(7,2)) ROW format delimited fields terminated by '|' stored as orc;
insert overwrite table catalog_sales_orc select * from catalog_sales;
select count(*) from catalog_sales_orc;
select cs_sold_date_sk,count(*) from catalog_sales_orc group by cs_sold_date_sk limit 1;
SequenceFile
CREATE EXTERNAL TABLE `catalog_sales_sequence`( `cs_sold_date_sk` bigint, `cs_sold_time_sk` bigint, `cs_ship_date_sk` bigint, `cs_bill_customer_sk` bigint, `cs_bill_cdemo_sk` bigint, `cs_bill_hdemo_sk` bigint, `cs_bill_addr_sk` bigint, `cs_ship_customer_sk` bigint, `cs_ship_cdemo_sk` bigint, `cs_ship_hdemo_sk` bigint, `cs_ship_addr_sk` bigint, `cs_call_center_sk` bigint, `cs_catalog_page_sk` bigint, `cs_ship_mode_sk` bigint, `cs_warehouse_sk` bigint, `cs_item_sk` bigint, `cs_promo_sk` bigint, `cs_order_number` bigint, `cs_quantity` int, `cs_wholesale_cost` decimal(7,2), `cs_list_price` decimal(7,2), `cs_sales_price` decimal(7,2), `cs_ext_discount_amt` decimal(7,2), `cs_ext_sales_price` decimal(7,2), `cs_ext_wholesale_cost` decimal(7,2), `cs_ext_list_price` decimal(7,2), `cs_ext_tax` decimal(7,2), `cs_coupon_amt` decimal(7,2), `cs_ext_ship_cost` decimal(7,2), `cs_net_paid` decimal(7,2), `cs_net_paid_inc_tax` decimal(7,2), `cs_net_paid_inc_ship` decimal(7,2), `cs_net_paid_inc_ship_tax` decimal(7,2), `cs_net_profit` decimal(7,2)) ROW format delimited fields terminated by '|' stored as sequencefile;
insert overwrite table catalog_sales_sequence select * from catalog_sales;
select count(*) from catalog_sales_sequence;
select cs_sold_date_sk,count(*) from catalog_sales_sequence group by cs_sold_date_sk limit 1;
RCFile
CREATE EXTERNAL TABLE `catalog_sales_rc`( `cs_sold_date_sk` bigint, `cs_sold_time_sk` bigint, `cs_ship_date_sk` bigint, `cs_bill_customer_sk` bigint, `cs_bill_cdemo_sk` bigint, `cs_bill_hdemo_sk` bigint, `cs_bill_addr_sk` bigint, `cs_ship_customer_sk` bigint, `cs_ship_cdemo_sk` bigint, `cs_ship_hdemo_sk` bigint, `cs_ship_addr_sk` bigint, `cs_call_center_sk` bigint, `cs_catalog_page_sk` bigint, `cs_ship_mode_sk` bigint, `cs_warehouse_sk` bigint, `cs_item_sk` bigint, `cs_promo_sk` bigint, `cs_order_number` bigint, `cs_quantity` int, `cs_wholesale_cost` decimal(7,2), `cs_list_price` decimal(7,2), `cs_sales_price` decimal(7,2), `cs_ext_discount_amt` decimal(7,2), `cs_ext_sales_price` decimal(7,2), `cs_ext_wholesale_cost` decimal(7,2), `cs_ext_list_price` decimal(7,2), `cs_ext_tax` decimal(7,2), `cs_coupon_amt` decimal(7,2), `cs_ext_ship_cost` decimal(7,2), `cs_net_paid` decimal(7,2), `cs_net_paid_inc_tax` decimal(7,2), `cs_net_paid_inc_ship` decimal(7,2), `cs_net_paid_inc_ship_tax` decimal(7,2), `cs_net_profit` decimal(7,2)) ROW format delimited fields terminated by '|' stored as rcfile;
insert overwrite table catalog_sales_rc select * from catalog_sales;
select count(*) from catalog_sales_rc;
select cs_sold_date_sk,count(*) from catalog_sales_rc group by cs_sold_date_sk limit 1;
AVRO
CREATE EXTERNAL TABLE `catalog_sales_avro`( `cs_sold_date_sk` bigint, `cs_sold_time_sk` bigint, `cs_ship_date_sk` bigint, `cs_bill_customer_sk` bigint, `cs_bill_cdemo_sk` bigint, `cs_bill_hdemo_sk` bigint, `cs_bill_addr_sk` bigint, `cs_ship_customer_sk` bigint, `cs_ship_cdemo_sk` bigint, `cs_ship_hdemo_sk` bigint, `cs_ship_addr_sk` bigint, `cs_call_center_sk` bigint, `cs_catalog_page_sk` bigint, `cs_ship_mode_sk` bigint, `cs_warehouse_sk` bigint, `cs_item_sk` bigint, `cs_promo_sk` bigint, `cs_order_number` bigint, `cs_quantity` int, `cs_wholesale_cost` decimal(7,2), `cs_list_price` decimal(7,2), `cs_sales_price` decimal(7,2), `cs_ext_discount_amt` decimal(7,2), `cs_ext_sales_price` decimal(7,2), `cs_ext_wholesale_cost` decimal(7,2), `cs_ext_list_price` decimal(7,2), `cs_ext_tax` decimal(7,2), `cs_coupon_amt` decimal(7,2), `cs_ext_ship_cost` decimal(7,2), `cs_net_paid` decimal(7,2), `cs_net_paid_inc_tax` decimal(7,2), `cs_net_paid_inc_ship` decimal(7,2), `cs_net_paid_inc_ship_tax` decimal(7,2), `cs_net_profit` decimal(7,2)) ROW format delimited fields terminated by '|' stored as avro;
insert overwrite table catalog_sales_avro select * from catalog_sales;
select count(*) from catalog_sales_avro;
select cs_sold_date_sk,count(*) from catalog_sales_avro group by cs_sold_date_sk limit 1;