Impala性能调优

一、给表分区

这个都知道,默认一个表的数据都是放在一个目录下的,对表分区,能够创建一些子目录,查询的时候,指定相应的条件能够实现只去相应的分区下查找数据,。
那么,什么情况下应该对表分区呢?
1)表非常的大。读整表会耗时很久
2)对表的查询几乎总是要涉及到用来分区的行作为刷选条件。如果对该表的查询几乎都不会采用分区行来作为条件,对表分区就没多大意义了,有时甚至还会适得其反。
3)用来分区的行应该有个合理的基数(不同值得数量)。如果行的取值很少,比如性别只有男和女,那你每次读取查询的时候也就最多忽略50%的数据,这并不能提高多少效率。另一方面,如果取值太多,那子目录也就相应的很多,每个子目录的数据文件会很小,而hadoop是以几十M的block传输数据的,显然这样就发挥不了优势。

怎么检测一个查询是否很好的利用的分区?也就是是否合理的进行了“分区裁剪”?
执行explain,通常返回的信息中会包含类似如下内容:

00:SCAN HDFS [df.operations]                                                      |
|    partitions=1/413 files=6 size=5.40GB                                                   |
|    predicates: uid IS NOT NULL, uid != '', uid != 'null'

其中的partitions就可以看出你的分区裁剪情况。例子中的取值为 1/413。也就是这个查询只会查询表对应目录下的413个子目录的一个。

执行完一条查询命令后,紧接着执行SUMMAY或者PROFILE。可以看到详细的查询分析

Note: If you are creating a partition for the first time and specifying its location, for maximum efficiency, use a single ALTER TABLE statement including both the ADD PARTITION and LOCATION clauses, rather than separate statements with ADD PARTITION and SET LOCATION clauses.

二、JOIN查询的性能考虑

一个join查询的结果集的最大尺寸是所有join表的行的乘积。所以如果是join一些有几百万或者几亿行的表,任何低效的查询都有可能导致查询无法完成而不得不取消查询。

对于join查询,最简单的方式是通过执行COMPUTE STATS来收集涉及到的所有表的统计信息,并让 Impala 基于每一个表的大小、每一个列不同值的个数、等等信息自动的优化查询。
如果没有表的统计信息,或 Impala 选择的连接顺序不是最优,你可以通过在 SELECT 关键字之后立刻紧跟 STRAIGHT_JOIN 关键字,来覆盖自动的连接顺序优化。这时候,Impala 使用表在查询中出现的顺序来指导连接如何处理。
如果使用STRAIGHT_JOIN,就不能再依赖Impala自身的优化器,而是需要手动来设置表的顺序。手工排序是一种启发式的方法,通过实验一步步来调优顺序:
1)最大的表放首位。这个表在查询的时候是每个impala节点直接从磁盘读取的,因此它的大小对于内存使用没影响。
2)然后按表大小有大到小依次排序。这些表的内容全部都是要在网络中传递的,所以,表越到后面越小越好。
值得注意的一点是,这里的“大小”是就每个表在查询后生成的中间结果涉及到的行的数量来定的。比如,一次查询,要join两个表:销售表和用户表。查询的结果是100个不同的用户共有5000条消费记录。因为涉及用户表的行比销售表少(100<5000)。所以用户表应该放在后面(右边)。

依赖于表的绝对和相对的大小,Impala 查询计划器在执行连接查询的不同技术之间进行选择。广播连接(Broadcast joins) 是默认方式,右侧的表被认为比左侧的表小,并且它的内容被发送到查询涉及到的其他节点上。替代的技术称作分割连接(partitioned join) (与分区表无关),更适用于近乎相同大小的大型表的连接。使用这一技术,每一个表的部分内容被发送到对应的其他节点,然后这些行的子集可以并行处理。广播和分区连接的选择仍然依赖于连接中所有表的可用的、使用 COMPUTE STATS 语句手机的统计信息。
对查询执行 EXPLAIN 语句,查看该查询采用了哪种连接策略。如果你发现一个查询使用了广播连接,而你通过基准测试知道分割连接更高效,或者相反情况时,在查询上添加提示指定使用的精确的连接机制。
假如连接中的一些表的表或列统计信息不可用,Impala 仍然使用可用的那部分信息重新排列表,包含可用统计信息的表放在连接的左侧,按照整体大小和基数降序排列。没有统计信息的表被认为大小为 0,也就是说,它们总是放置在连接查询的右侧。

善用STRAIGHT_JOIN。前面已经对STRAIGHT_JOIN。简单来说就是,有时候会出现过时的统计信息和不可预知的数据分布,这时候如果还依赖impala自身的优化器来安排表的join顺序就会造成低效的查询。而STRAIGHT_JOIN能够关闭这种内在的优化,而基于你的sql。这时写sql的时候就要坚持将越大的表放在越前面了。

在下面的例子里,基于 BIG 表的子查询产生一个非常小的结果集,但是这个表仍被视为好像它是最大的并放置在连接顺序的第一位。为最后的连接子句使用 STRAIGHT_JOIN 关键字,防止最终的表重新排序,保持它作为最右边表的连接顺序

select straight_join x from medium join small join (select * from big where c1 < 10) as big where medium.id = small.id and small.id = big.id;

三、表和列的统计信息

impala1.2.2之前,impala只能依赖Hive的ANALYZE TABLE 来收集统计信息,1.2.2后,有了COMPUTE STATS来获取。

为了查看表的统计信息,可以使用SHOW TABLE STATS table_name语句。

分区表通常都是在不断变大的。这时候如果增加或者更新一个新分区也需要执行COMPUTE STATS的话,是非常低效的。因为COMPUTE STATS需要遍历整张表。为了解决这个问题,从impala1.2开始,增加了COMPUTE INCREMENTAL STATS。这个命令只会增量统计信息。

对于通量的数据,执行COMPUTE INCREMENTAL STATS会比执行COMPUTE STATS更耗时。因此更适合要频繁增加具有大量数据的分区的表。对于不分区的表,或者虽然分区,但一次加载,不会再更新新分区的表,使用COMPUTE STATS更好。

如果使用ALTER TABLE来删除一列,存在的统计信息仍然有效,执行COMPUTE INCREMENTAL STATS不会重新扫描任何分区;
如果使用ALTER TABLE来增加一列,执行COMPUTE INCREMENTAL STATS时,impala会重新扫描所有分区,并填充准确的列层级的值;
如果使用ALTER TABLE来改变表的文件格式,存在的统计信息仍然有效,执行COMPUTE INCREMENTAL STATS不会重新扫描任何分区;
如果使用ALTER TABLE来改变某列的数据类型,执行COMPUTE INCREMENTAL STATS时,impala会重新扫描所有分区,并填充准确的列层级的值;

四、impala性能最佳实践

1)根据数据大小选择合适的文件格式。对于每个表或分区都达很多G的数据,使用Parquet是性能表现最好的。
2)基于数据大小选择分区粒度。通常来说,最好保证每个分区的数据不小于256MB。过度分区会导致查询很多不需的分区而造成查询太长。理想情况下,表的分区数要低于3万个。在每个分区目录下,保存的文件应该是几个大文件,而不要保存很多小文件。如果接收的数据本身是很多小文件,要考虑使用INSERT …SELECT语句将一个表或分区的数据复杂到其他表或分区,这会压缩文件达到较少的数量。
3)选择一个合适的Parquet block尺寸。
4)将传输结果回客户端的最小负载最小化。
5)验证你的查询的逻辑是不是高效的。执行之前,通过EXPLAIN检测一下。
6)验证查询的性能特征。IO、内存使用、网络带宽、CPU利用率等等。
7)使用合适的操作系统设置

你可能感兴趣的:(hadoop,hive)