1. 将表分区(Partitioned Table)
通过将表划分为相互独立的分区,对应于HDFS上相互独立数据目录,在查询时通过指定分区列上的条件,将读取数据的范围限定在关心的数据上,而不需要读取全表数据,继而提升查询性能;
通过CREATE TABLE语句实现。
2. 分桶(Bucked Table)
所谓分桶就是将表中的内容以某列为基准,对所指定的桶的个数N进行模运算,继而将数据划分成N份,对应于HDFS上的N个文件。桶的划分进一步细化了文件读取的粒度,这样在做JOIN时,如果两边的表使用相同的方式进行了分桶,左边表的桶就知道所对应右边表的桶,从而优化读取过程;如果再在分桶的同时,对分桶列进行排序,那么这个JOIN过程将会进行高效地合并排序,性能得到进一步提升。
3. 合理使用文件存储格式并使用压缩
目前Hadoop支持很多的文件存储格式,面向行的包括原始的TEXT、Avro、SequenceFile;还有面向列的,如Parquet、RCFile、ORCFile等。对于选择面向行的存储还是面向列的存储,需要根据具体的使用场景选择,如果每次只读取表中全部列的一小部分那么,面向列的存储可能会大幅度减少每次读取的数据量,反之,使用面向行的数据存储格式可能效率会更好。
在正确选择存储格式的同时,通过压缩相应的存储文件,进一步降低读取时的IO压力,会进一步提升运行效率。
4. 对Hive中间结果进行压缩,减少Map端向Reduce端传输的网络IO
MapReduce计算过程中会将Map输出的中间结果落地,然后通过网络传输将中间结果交由Reduce处理,通过压缩将需要写入到本地磁盘和通过网络传输的数据量大幅减少,继而提升整个MapReduce过程的效率。
5. 通过使用部分排序而非全局排序使Reduce阶段更加并行化
如果使用ORDER BY进行排序,会对全部的数据进行排序,最终会将排序过程在一个Reduce过程中处理,即便是归并排序,但这对于数据量较大的情况是非常低效的;通过使用SORT BY可以为每个Reduce生成一个排序文件。
一般要与DISTRIBUTE BY同时使用,将对应列的每个值的所有的记录分配到一个分区中。
6. 数据量较大时避免使用COUNT DISTINCT
如果最后大量的数据都倾斜到一个Reduce中进行操作,会造成Reduce端的效率低下;建议先进行GROUP BY,然后再在外层进行COUNT(1)计算。
7. 使用Presto并配置Hive数据源
由于使用了完全不同于MapReduce的计算过程,克服了MapReduce过程中的许多问题,缓存的使用,减少数据落地过程的IO,很大地提升了查询的相应速度。尽管PrestoSQL同HiveSQL有一些不同之处,但是只需要经过简单的调整即可。再考虑到,Presto可以对接除Hive之外的其它数据源,如Kafka、关系数据库、Redis等,并将其数据置于统一的查询视图下,整个数据体系的扩展性和灵活性得以提升。