Hive 优化之为外部表创建分区

首先,我们有一个数据量很大的表。其次,对他进行条件查询或其他操作就像看着一只小蜗牛在爬。

是可忍,孰不可忍!

0x01 原理

关于分区为什么能提升查询速度,这就值得你仔细想想了。

既然 hive 基于文件系统,那么我们可以把它类比成很多个桶。

假设现在有 100 个桶,分别存放不同的海鲜,其中 2 个桶里有我们想要的桂花鱼,1 个桶里有阿根廷大红虾,那如何才能在最快的速度找出这 3 个桶?

按照默认的策略,人们会打开盖子一桶一桶找,而如果有 1000、10000 个桶,就会从一个人找演变成一群人一起找。

有没有改进方式呢?有。

有一天老板发现,不对啊,这个事我居然叫那么多人来做,感觉自己额外付出了很多成本,亏钱了。不行!这个事情必须改革!于是他思前想后好几天怎么也也想不到更好的办法,也因此懊恼了许久。直到有一天,老板夫人得了风寒,老板十分心急,替夫人去药铺抓药,当它看见郎中拿着方子在药柜抓药的时候,心中的郁结终于揭开了。拍了拍脑瓜子,大叫了声,对呀!我怎么没想到呢!

于是,从药铺回来后,老板更改了新的存鱼策略。它让员工们把鱼放进桶里的同时,在桶外贴上标签,取鱼的时候只需要远远地扫一眼就能快速定位。

hive 也是如此,你可以粗略地将它的存储系统理解为,将一堆文件放在同一个文件夹里,需要的时候在这堆文件里遍历,最后的效果不言而喻。

分区的好处便是,将文件按一定的维度,存进不同的文件夹,相当于给他们打好了标签,这样我按这个维度搜索时,便不需要遍历其他无关的文件。数据越多,对查询效率的提升就越大。

0x02 操作一波

首先看分区列表,如果结果为空就表示该表下没有分区。

1
show partitions tmp.tmp_user;

给当前表添加分区

1
alter table tmp.tmp_user add partition (month='2018_10', day='25') location '/user/amos/tmp_user/month=2018_10/day=25';

将数据迁移至分区中

1
$ hdfs dfs -mv /user/amos/tmp_user/data_20181025.csv /user/amos/tmp_user/month=2018_10/day=25

物极必反

为了提升搜索效果,增加分区数是可以的,但是如果分区数太过庞大,而需查询的数据也很多的话,分区带来的提升会被弱化。尤其是在分区中数据较为分散的时候,只要查询数据量达到一定量级便会轻易集中所有分区。

大量分区带来的不良后果不仅如此,还会在查询之后给磁盘带来更多的小文件。

说点题外话

如果是对数据仓库进行优化

hive 中,有几种办法

  • 分区
  • 分桶
  • 索引
  • 区分活跃用户
  • 更改数据结构(id - string –> id - list)