LanguageManual JoinOptimization
Improvementsto the Hive Optimizer
Hive可以自动优化,在Hive 0.11里面改进了一些优化用例
1、 JOIN的一边适合放在内存,有新的优化方案
a) 把表按照hash表的形式读进内存
b) 只扫描大表
c) fact表只使用少量内存
2、 星型join
3、 在很多情况下,不再需要hint
4、 Map Join自动优化
StarJoin Optimization
先介绍一下星型模型和雪花型模型
===================开始=======================
1、简介
星形模式是一种多维的数据关系,它由一个事实表(FactTable)和一组维表(Dimension Table)组成。每个维表都有一个维作为主键,所有这些维的主键组合成事实表的主键。事实表的非主键属性称为事实(Fact),它们一般都是数值或其他可以进行计算的数据;而维大都是文字、时间等类型的数据,按这种方式组织好数据我们就可以按照不同的维(事实表主键的部分或全部)来对这些事实数据进行求和(summary)、求平均(average)、计数(count)、百分比(percent)的聚集计算,甚至可以做20~80分析。这样就可以从不同的角度数字来分析业务主题的情况。
在多维分析的商业智能解决方案中,根据事实表和维度表的关系,又可将常见的模型分为星型模型和雪花型模型。在设计逻辑型数据的模型的时候,就应考虑数据是按照星型模型还是雪花型模型进行组织。
当所有维表都直接连接到“ 事实表”上时,整个图解就像星星一样,故将该模型称为星型模型, 如图 2 。
星型架构是一种非正规化的结构,多维数据集的每一个维度都直接与事实表相连接,不存在渐变维度,所以数据有一定的冗余,如在地域维度表中,存在国家 A 省 B 的城市 C 以及国家 A 省 B 的城市 D 两条记录,那么国家 A 和省 B 的信息分别存储了两次,即存在冗余。
下图为销售数据仓库中的星型模型:
当有一个或多个维表没有直接连接到事实表上,而是通过其他维表连接到事实表上时,其图解就像多个雪花连接在一起,故称雪花模型。雪花模型是对星型模型的扩展。它对星型模型的维表进一步层次化,原有的各维表可能被扩展为小的事实表,形成一些局部的 " 层次 " 区域,这些被分解的表都连接到主维度表而不是事实表。如图 2,将地域维表又分解为国家,省份,城市等维表。它的优点是 : 通过最大限度地减少数据存储量以及联合较小的维表来改善查询性能。雪花型结构去除了数据冗余。
下图为销售数据仓库中的雪花型模型:
星型模型因为数据的冗余所以很多统计查询不需要做外部的连接,因此一般情况下效率比雪花型模型要高。星型结构不用考虑很多正规化的因素,设计与实现都比较简单。雪花型模型由于去除了冗余,有些统计就需要通过表的联接才能产生,所以效率不一定有星型模型高。正规化也是一种比较复杂的过程,相应的数据库结构设计、数据的 ETL、以及后期的维护都要复杂一些。因此在冗余可以接受的前提下,实际运用中星型模型使用更多,也更有效率。
2、使用选择
星形模型(StarSchema)和雪花模型(SnowflakeSchema)是数据仓库中常用到的两种方式,而它们之间的对比要从四个角度来进行讨论。
1)数据优化
雪花模型使用的是规范化数据,也就是说数据在数据库内部是组织好的,以便消除冗余,因此它能够有效地减少数据量。通过引用完整性,其业务层级和维度都将存储在数据模型之中。
▲图1 雪花模型
相比较而言,星形模型实用的是反规范化数据。在星形模型中,维度直接指的是事实表,业务层级不会通过维度之间的参照完整性来部署。
▲图2 星形模型
2)业务模型
主键是一个单独的唯一键(数据属性),为特殊数据所选择。在上面的例子中,Advertiser_ID就将是一个主键。外键(参考属性)仅仅是一个表中的字段,用来匹配其他维度表中的主键。在我们所引用的例子中,Advertiser_ID将是Account_dimension的一个外键。
在雪花模型中,数据模型的业务层级是由一个不同维度表主键-外键的关系来代表的。而在星形模型中,所有必要的维度表在事实表中都只拥有外键。
3)性能
第三个区别在于性能的不同。雪花模型在维度表、事实表之间的连接很多,因此性能方面会比较低。举个例子,如果你想要知道Advertiser 的详细信息,雪花模型就会请求许多信息,比如AdvertiserName、ID以及那些广告主和客户表的地址需要连接起来,然后再与事实表连接。
而星形模型的连接就少的多,在这个模型中,如果你需要上述信息,你只要将Advertiser的维度表和事实表连接即可。
4)ETL
雪花模型加载数据集市,因此ETL操作在设计上更加复杂,而且由于附属模型的限制,不能并行化。
星形模型加载维度表,不需要再维度之间添加附属模型,因此ETL就相对简单,而且可以实现高度的并行化。
总结
雪花模型使得维度分析更加容易,比如“针对特定的广告主,有哪些客户或者公司是在线的?”星形模型用来做指标分析更适合,比如“给定的一个客户他们的收入是多少?”
===================结束=======================
在决策支持系统或者数据仓库中,一个简单的模式是星型模式,事件都是存储在大的事实表(facttables)里面的,很多小的维表(dimensions)来描述事实表中的数据。
TPC DS就是星型模式中的一个例子。
1、StarSchema Example
Selectcount(*) cnt
Fromstore_sales ss
join household_demographics hd on(ss.ss_hdemo_sk = hd.hd_demo_sk)
join time_dim t on (ss.ss_sold_time_sk =t.t_time_sk)
join store s on (s.s_store_sk =ss.ss_store_sk)
Where
t.t_hour = 8
t.t_minute >= 30
hd.hd_dep_count = 2
order by cnt;
2、PriorSupport for MAPJOIN
Hive支持MAPJOINS,很适合这个方案-至少对于dimensions小到足够放到内存。
在Hive 0.11之前,hive.auto.convert.join默认值为false,如果需要使用MAPJOIN,则使用优化器hint方式:
select/*+ MAPJOIN(time_dim) */ count(*) from
store_sales join time_dimon (ss_sold_time_sk = t_time_sk);
或者通过设置参数后自动进行mapjoin:
sethive.auto.convert.join=true;
selectcount(*) from
store_sales join time_dimon (ss_sold_time_sk = t_time_sk);
在Hive 0.11.0开始,hive.auto.convert.join默认值为true。
MAPJOINS把小表hash map的形式读进内存,然后和大表匹配key,以下是各阶段的分工:
1) Localwork:本地
•readrecords via standard table scan (including filters and projections) from sourceon local machine --------扫描表
•buildhashtable in memory -------在内存中建立hash表
•writehashtable to local disk --------hash表写进本地磁盘
•uploadhashtable to dfs -----------上传hash表到hdfs
•add hashtable to distributed cache --------把hash表加进分布式缓存
2) Maptask:Map任务
•readhashtable from local disk (distributed cache) into memory ------从本地磁盘(分布式缓存)把hash表读进内存
•matchrecords' keys against hashtable --------与hash表匹配key
•combine matches and write to output --------合并匹配,并写出output
3) Noreduce task:MapJoin特点,没有reduce
Limitationsof Prior Implementation
MAPJOIN在Hive 0.11之前有如下的一些限制:
1) 一个mapjoin只能一次处理一个key,它可以执行多表连接,但只有当所有的表都加入了相同的key。(典型的星型连接不属于这一类)
2) 就算是加了hint也未必真的使用mapjoin。
3) 一连串的mapjoins不会合并成一个单一的map job,除非查询写成一个级联的mapjoin(mapjoin(table,subquery(mapjoin(table, subquery....).自动转换后的也不会变成一个单一的map job。
4) mapjoin中用到的哈希表,每个子QUERY运行都会生成,先下载,再分发给map。
Enhancementsfor Star Joins
调优主要从三方面入手的:
1) 使用MapJoinHint时,把一连串的MapJoin操作变成一个map-only的job。
2) 把优化方案尽可能的变成自动优化(顺便备份下执行计划)。
3) 使得hashtable在taskside(map端)直接生成,现在的方案是先在本地生成,然后传到HDFS,再分布式缓存去分给每个map,未来版本会实现。
下面部分将描述每个优化加强方面:
OptimizeChains of Map Joins
下面的SQL会被分解为2个独立的map-only jobs执行:
select/*+ MAPJOIN(time_dim, date_dim) */ count(*) from
store_sales
jointime_dim on (ss_sold_time_sk = t_time_sk)
joindate_dim on (ss_sold_date_sk = d_date_sk)
where t_hour = 8 andd_year = 2002;
将小表读进内存,如果fact只读了一次,而不是2次,那么会极大的减少执行时间。
Current and Future Optimizations 当前和未来调优的方向
1) MergeM*-MR patterns into a single MR. ----把多个map-only的job+MRjob的模式变成单个MR
2) MergeMJ->MJ into a single MJ when possible. -----尽可能的把mapjoin嵌套模式变成一个mapjoin
3) Merge MJ* patterns intoa single Map stage as a chain of MJ operators. (Not yet implemented.) ------------把多个mapjoin串起来,变成一连串的mapjoin(上面的例子是分成两个独立的map-only的job,而不是一连串的,功能暂未实现)
如果hive.auto.convert.join为true的话,不仅仅会将join转化为mapjoin,还有可能转化成MJ*这种模式。
OptimizeAuto Join Conversion
当auto join打开时,就不再需要使用hint了,参数有两个:
sethive.auto.convert.join.noconditionaltask = true;
Hive0.11.0开始默认为true
sethive.auto.convert.join.noconditionaltask.size = 10000000;
小于这个size的表被放入内存,这个size大小指的是被放进内存的hash表的大小总和,当前版本,n-1个表都可以被放进内存,最大的那个表放在磁盘上match。在这里不会去检查表是否被压缩,直接从HDFS中得到的file大小。
之前的例子就可以变成:
selectcount(*) from
store_sales
jointime_dim on (ss_sold_time_sk = t_time_sk)
joindate_dim on (ss_sold_date_sk = d_date_sk)
where t_hour = 8 andd_year = 2002;
如果这2个维表的大小符合config的size,就会转换成map-join(2个).。这里的size 我认为应该是指hive.smalltable.filesize 这个值 默认25m。
如果维表的总和小于noconditionaltask.size 会把2个map-join 合并成一个。这样做减少了MR job的数量,并显著提高了query的速度。.这个例子可以很容易地扩展为muti-way join 以及将按预期工作。
外连接不能用map-join。因为map-join 只能有一个steam表,steam表的所有column都应该是全的,外连接可能出现null。
这意味着外连接不能用,只有内连接才能map-join。外连接只能用stream table的形式来调优了。笛卡尔积就更别说了,无法使用map-jon。
自动开关也可以作用在sort-merge-bucketjoins
CurrentOptimization 当前的优化方案
把多个MJ合并成一个MJ。
AutoConversion to SMB(Sort-Merge-Bucket) Map Join
基于桶的join,可以转换成为基于桶的map join。
前提是表按照桶划分的。排过序的表会比没有排序的表做map join更快。如果表又是分区表,又是bucket表,可能会慢一点,因为每个mapper需要去获取一个单键分区中的一小块(eachmapper would need to get a very small chunk of a partition which has a singlekey)。
下面的配置参数使一个SMB转为map-joinSMB:
sethive.auto.convert.sortmerge.join=true;
sethive.optimize.bucketmapjoin = true;
sethive.optimize.bucketmapjoin.sortedmerge = true;
sethive.auto.convert.sortmerge.join.noconditionaltask=true;
这里有一个选项去设置大表选择策略(big table selection policy):
set hive.auto.convert.sortmerge.join.bigtable.selection.policy
= org.apache.hadoop.hive.ql.optimizer.TableSizeBasedBigTableSelectorForAutoSMJ;
默认情况下为平均分区大小,这个大表策略有助于确定选择stream,相比是hash还是流来说的。
可用的选择策略列表是:
org.apache.hadoop.hive.ql.optimizer.AvgPartitionSizeBasedBigTableSelectorForAutoSMJ(default)
org.apache.hadoop.hive.ql.optimizer.LeftmostBigTableSelectorForAutoSMJ
org.apache.hadoop.hive.ql.optimizer.TableSizeBasedBigTableSelectorForAutoSMJ
从名字上面就可以判断用途,特别是用在fact和fact的join中。
GenerateHash Tables on the Task Side
未来的版本,可能会把哈希放到task side(当前是放在客户端生成的)。
Prosand Cons of Client-Side Hash Tables (在客户端生成hash表的优缺点)
无论是生成哈希,还是多表的哈希join都有问题。因为客户端的机器都是用来跑hive客户端或者用来提交job的。
缺点:
•Data locality: The client machine typically is not a data node. Allthe data accessed is remote and has to be read via the network.
数据分布:客户端机器一般都不是数据节点,所有的数据访问都是远程的,必须通过网络读取。
•Specs: For the same reason, it is not clear what the specificationsof the machine running this processing will be. It might have limitations inmemory, hard drive, or CPU that the task nodes do not have.
空间:出于同样的原因,这是不清楚的机器有点什么。任务节点上的内存,硬盘,cpu情况不清楚。
•HDFS upload: The data has to be brought back to the clusterand replicated via the distributed cache to be used by task nodes.
HDFS数据上传:数据返回到集群和被复制都要通过task节点的分布式缓存。
好处:
•What is stored in the distributed cache islikely to be smaller than the original table (filter and projection).
因为做了filter或者投影,生成的哈希表(到分布式缓存)可能比原始的表要小。
•In contrast, loading hashtables directly onthe task nodes using the distributed cache means larger objects in the cache,potentially reducing opportunities for using MAPJOIN.
相比之下,如果在task端直接使用分布式缓存加载哈希表,意味着缓存会占用大表占用,间接的减少使用mapjoin的可能性。
Task-SideGeneration of Hash Tables task端生成哈希
当在task端生成哈希时,所有任务节点必须访问原始数据源生成的哈希表(同时去访问统一资源)。在正常情况下,这一操作是并行的,不会导致延迟,但是hive有一个概念,就是多任务同时访问外部的数据源,如HBase,Database等,这样就有可能导致延迟了。
FurtherOptions for Optimization 未来的优化方向
1.Increasethe replication factor on dimension tables. ----增加维表的复制因子
2.Use the distributedcache to hold dimension tables. ----使用分布式缓存来存放维表