以下部分介绍了影响Impala功能性能的因素,以及调整,监视和基准测试Impala查询和其他SQL操作的过程。
本节还介绍了最大化Impala可扩展性的技术。 可扩展性与性能相关:它意味着随着系统工作负载的增加,性能仍然很高。 例如,减少执行的磁盘I / O.
通过查询可以加速单个查询,同时通过使同时运行更多查询变得切实可行来提高可扩展性。 有时,优化技术比性能更能提高扩展性。 例如,减少查询的内存使用量可能不会大大改变查询性能,但可以通过允许更多Impala查询或其他类型的作业同时运行而不会耗尽内存来提高可扩展性。
以下是在启用Impala的群集的规划,实验和性能调整期间可以使用的性能指南和最佳实践。
通常,对于大量数据(每个表或分区多个千兆字节),Parquet文件格式的性能最佳,因为它结合了列式存储布局,大I / O请求大小以及压缩和编码。 有关所支持的所有文件格式的比较,请参见Impala如何与Hadoop文件格式配合使用
注意:对于每个表或分区的较小数据量(几千兆字节或更少),您可能看不到文件格式之间的显着性能差异。 在小数据量时,可以通过减少并行执行的机会来减少来自高效压缩文件格式的I / O减少。
在Impala之外生成数据文件时,更喜欢文本格式或Avro,您可以在其中逐行构建文件。一旦数据在Impala中,您就可以将其转换为更高效的Parquet格式,并使用单个INSERT … SELECT语句拆分为多个数据文件。
始终使用INSERT … SELECT在Impala中从表到表复制大量数据。避免对任何大量数据或性能关键表执行INSERT … VALUES,因为每个这样的语句都会生成一个单独的微小数据文件。有关INSERT … SELECT语法的示例。
例如,如果Parquet表中有数千个分区,每个分区的数据少于256 MB,请考虑以不太精细的方式进行分区,例如按年/月而不是年/月/日。如果低效的数据提取过程在同一个表或分区中产生数千个数据文件,请考虑通过执行INSERT … SELECT来压缩数据,以将所有数据复制到另一个表中;此过程将数据重组为较少数量的较大文件。
分区是一种基于一个或多个列的值物理划分数据的技术,例如按年,月,日,地区,城市,网站的部分等。当您发出请求分区键列的特定值或值范围的查询时,Impala可以避免读取不相关的数据,从而可能大大节省磁盘I / O.
在确定要用于分区的列时,请选择正确的粒度级别。例如,您应该按年,月和日进行分区,还是仅按年和月进行分区?选择在每个分区中至少放置256 MB数据的分区策略,以利用HDFS批量I / O和Impala分布式查询。
过度分区还可能导致查询计划花费的时间超过必要的时间,因为Impala会修剪不必要的分区。理想情况下,将表中的分区数保持在3万以下。
准备数据文件进入分区目录时,创建几个大文件而不是许多小文件。如果您以许多小文件的形式接收数据并且无法控制输入格式,请考虑使用INSERT … SELECT语法将数据从一个表或分区复制到另一个表或分区,这会将文件压缩为相对较小的数字(基于集群中的节点数)。
如果需要减少分区的总数并增加每个分区中的数据量,请首先查找很少引用或在非关键查询中引用的分区键列(不受SLA约束)。例如,您的网站日志数据可能按年,月,日和小时进行分区,但如果大多数查询按日汇总结果,则可能只需要按年,月和日进行分区。
如果您需要进一步降低粒度,请考虑创建“桶”,与不同的分区键值集对应的计算值。
尽管将字符串用于分区键列很有诱惑力,但由于这些值无论如何都会转换为HDFS目录名,因此可以通过对常用分区键字段(如YEAR,MONTH和DAY)使用数值来最小化内存使用量。 使用包含适当值范围的最小整数类型,通常为MONTH和DAY的TINYINT,以及YEAR的SMALLINT。 使用EXTRACT()函数从TIMESTAMP值中提取单个日期和时间字段,并将返回值CAST()提取到适当的整数类型。
默认情况下,Impala INSERT … SELECT语句创建块大小为256 MB的Parquet文件。 (此默认值在Impala 2.0中已更改。以前,限制为1 GB,但Impala对压缩做出了保守估计,导致文件小于1 GB。)
Impala编写的每个Parquet文件都是一个块,允许整个文件由单个主机作为一个单元进行处理。将Parquet文件复制到HDFS或HDFS文件系统之间时,请使用hdfs dfs -pb保留原始块大小。
如果Parquet表中只有一个或几个数据块,或者查询中唯一访问的分区,那么您可能会因为其他原因而遇到速度减慢:没有足够的数据来利用Impala的并行分布查询。每个数据块由其中一个DataNode上的单个核处理。在具有16核计算机的100节点集群中,您可以同时处理数千个数据文件。您希望在“许多小文件”和“单个巨型文件”之间找到一个可以平衡批量I / O和并行处理的最佳位置。您可以在执行INSERT … SELECT语句之前设置PARQUET_FILE_SIZE查询选项,以减小每个生成的Parquet文件的大小。 (将文件大小指定为绝对字节数,或者在Impala 2.0及更高版本中指定,以m表示兆字节或g表示千兆字节。)运行具有不同文件大小的基准,以找到特定数据卷的正确平衡点。
使用COMPUTE STATS语句收集统计信息。
使用如下技术:
聚合。如果您需要知道条件匹配的行数,某些列匹配值的总值,最低或最高匹配值等等,则调用聚合函数,如COUNT(),SUM()和MAX()在查询中,而不是将结果集发送到应用程序并在那里进行那些计算。请记住,未聚合的结果集的大小可能很大,需要大量时间才能通过网络传输。
过滤。使用查询的WHERE子句中的所有适用测试来消除不相关的行,而不是生成大的结果集并使用应用程序逻辑对其进行过滤。
LIMIT条款。如果您只需要从结果集中查看一些样本值,或者使用ORDER BY查看查询的顶部或底部值,请包含LIMIT子句以减小结果集的大小,而不是要求完整的结果集,然后将大部分行扔掉。
避免使用漂亮打印结果集并将其显示在屏幕上的开销。通过impala-shell检索结果时,使用impala-shell选项(如-B和–output_delimiter)生成没有特殊格式的结果,并将输出重定向到文件而不是打印到屏幕。考虑使用INSERT … SELECT将结果直接写入HDFS中的新文件。
在实际运行查询之前,请检查EXPLAIN 语句。 有关详细信息,请参见第283页的EXPLAIN语句和第664页的使用EXPLAIN计划进行性能调整。
通过在运行查询后检查查询的查询配置文件,验证I / O的低级别方面,内存使用情况,网络带宽,CPU利用率等是否在预期范围内。 有关详细信息,请参阅使用查询配置文件进行性能调整。
有关可以更改以影响Impala性能的操作系统设置的建议,请参阅Apache Hadoop发行版的文档。特别是,您可能会发现将vm.swappiness Linux内核设置更改为非零值可以提高整体性能。
在Impala的上下文中,热点被定义为“Impala守护程序,对于单个查询或工作负载,处理相对于其邻居的数据的时间要大得多”。
在讨论解决此问题的选项之前,首先需要了解一些背景知识,以了解如何发生此问题。
默认情况下,基于扫描的计划片段的调度是确定性的。这意味着对于需要读取相同数据块的多个查询,将选择相同的节点来承载扫描。默认的调度逻辑可以
不考虑先前查询的节点工作负载。实现元组的复杂性取决于几个因素,即:解码和解压缩。如果由于良好的编码/压缩比而将元组密集地打包到数据页中,则在重建数据时将需要更多的工作。每个压缩编解码器都提供不同的性能权衡,在编写数据之前应该考虑这些权衡。由于调度程序的确定性,单个节点可能成为使用相同表的高度并发查询的瓶颈。
例如,如果基于Parquet的数据集很小,例如一个小维度表,它适合单个HDFS块(默认情况下Impala将在使用Parquet时创建256 MB块,每个块包含一个单行组)然后有许多选项可以考虑解决这个问题查询此数据时调度热点:
在Impala 2.5及更高版本中,可以使用以下查询选项更改调度程序的确定性行为:REPLICA_PREFERENCE和RANDOM_REPLICA。有关这些模式的详细说明,请参阅IMPALA-2696。
HDFS缓存可用于缓存块副本。这将导致Impala调度程序随机选择(从Impala 2.2和更高版本)一个节点,该节点承载用于扫描的缓存块副本。注意,虽然HDFS缓存有好处,但它只能帮助读取原始块数据而不是缓存的元组数据,但是具有正确数量的缓存副本(默认情况下,HDFS只缓存一个副本),甚至负载分配也可以实现了较小的数据集。
不要压缩表数据。未压缩的表数据跨越更多节点并消除由压缩引起的偏斜。
在写入表数据时,通过PARQUET_FILE_SIZE查询选项减少Parquet文件大小。使用此方法,数据将跨越更多节点。但是,建议不要将大小降至32 MB以下。
涉及连接操作的查询通常需要比仅引用一个表的查询更多的调优。连接查询的结果集的最大大小是所有连接表中行数的乘积。当连接具有数百万或数十亿行的多个表时,任何错过的过滤结果集的机会或查询中的其他低效率可能导致操作在实际时间内没有完成并且必须被取消。
调整Impala连接查询的最简单方法是收集连接中涉及的每个表的统计信息使用COMPUTE STATS语句,然后让Impala根据每个表的大小,每列的不同值的数量等自动优化查询。 COMPUTE STATS语句和连接优化是Impala 1.2.2中引入的新功能。有关每个表的准确统计信息,请在将数据加载到该表后发出COMPUTE STATS语句,如果由于INSERT,LOAD DATA,添加分区等导致数据量发生重大变化,则再次发出。
如果连接查询中的所有表都没有统计信息,或者Impala选择的连接顺序不是最有效,则可以通过在SELECT和任何DISTINCT或ALL之后立即指定STRAIGHT_JOIN关键字来覆盖自动连接顺序优化关键字。在这种情况下,Impala使用表在查询中出现的顺序来指导联接的处理方式。
使用STRAIGHT_JOIN技术时,必须手动在连接查询中对表进行排序,而不是依赖Impala优化器。优化程序使用复杂的技术来估计连接的每个阶段的结果集的大小。对于手动排序,请使用此启发式方法开始,然后尝试微调订单:
首先指定最大的表。每个Impala节点都从磁盘读取此表,因此在查询期间,其大小在内存使用方面并不重要。
接下来,指定最小的表。表,第二,第三等表的内容都通过网络传输。您希望最小化连接查询的每个后续阶段的结果集的大小。最可能的方法是首先加入一个小表,这样即使处理后续较大的表,结果集仍然很小。
加入下一个最小的表,然后是下一个最小的表,依此类推。
例如,如果你有表BIG,MEDIUM,SMALL和TINY,那么尝试的逻辑连接顺序将是BIG,TINY,SMALL,MEDIUM。
术语“最大”和“最小”是指基于作为结果集一部分的每个表的行数和列数的中间结果集的大小。例如,如果您将一个表销售与另一个表客户联系在一起,则查询可能会找到来自100个不同客户的结果,这些客户总共进行了5000次购买。在这种情况下,您将指定SELECT … FROM sales JOIN customers …,将客户放在右侧,因为它在此查询的上下文中较小。
Impala查询计划程序在执行连接查询的不同技术之间进行选择,具体取决于表的绝对大小和相对大小。广播连接是默认设置,其中考虑了右侧表
小于左侧表,其内容被发送到查询中涉及的所有其他节点。替代技术称为分区连接(与分区表无关),它更适合大小相等的大型表。利用这种技术,每个表的部分被发送到适当的其他节点,其中可以并行处理那些行的子集。广播或分区连接的选择还取决于COMPUTE STATS语句收集的连接中所有表的可用统计信息。
要查看用于特定查询的连接策略,请为查询发出EXPLAIN语句。如果在通过基准测试知道分区连接效率更高(或反之亦然)时发现查询使用广播连接,请在查询中添加提示以指定要使用的精确连接机制。
如果联接中的某些表不能使用表或列统计信息,则Impala仍会使用可用的信息对表进行重新排序。具有统计信息的表格放置在连接顺序的左侧,按照总体大小和基数的成本降序排列。没有统计信息的表被视为零大小,也就是说,它们始终位于连接顺序的右侧。
如果由于过时的统计信息或意外的数据分发而导致Impala连接查询效率低下,则可以通过在SELECT和任何DISTINCT或ALL关键字之后立即使STRAIGHT_JOIN关键字来阻止Impala重新排序连接的表。 STRAIGHT_JOIN关键字关闭Impala在内部执行的连接子句的重新排序,并生成依赖于在查询文本中以最佳方式排序的连接子句的计划。
注意:
STRAIGHT_JOIN提示会影响包含提示的查询块中表引用的连接顺序。它不会影响嵌套查询的连接顺序,例如视图,内联视图或WHERE子句子查询。要使用此提示进行复杂查询的性能调整,请将提示应用于需要固定连接顺序的所有查询块。
在此示例中,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;
-- If the query contains [DISTINCT | ALL], the hint goes after those
keywords.
select distinct 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;
以下示例显示了具有10亿,2亿和1百万行的表之间的连接。 (在这种情况下,表是未分区的并使用Parquet格式。)较小的表包含来自最大的数据的子集,以便于加入唯一的ID列。 最小的表只包含其他列的列子集。
[localhost:21000] > create table big stored as parquet as select * from
raw_data;
+----------------------------+
| summary |
+----------------------------+
| Inserted 1000000000 row(s) |
+----------------------------+
Returned 1 row(s) in 671.56s
[localhost:21000] > desc big;
+-----------+---------+---------+
| name | type | comment |
+-----------+---------+---------+
| id | int | |
| val | int | |
| zfill | string | |
| name | string | |
| assertion | boolean | |
+-----------+---------+---------+
Returned 5 row(s) in 0.01s
[localhost:21000] > create table medium stored as parquet as select * from
big limit 200 * floor(1e6);
+---------------------------+
| summary |
+---------------------------+
| Inserted 200000000 row(s) |
+---------------------------+
Returned 1 row(s) in 138.31s
[localhost:21000] > create table small stored as parquet as select
id,val,name from big where assertion = true limit 1 * floor(1e6);
+-------------------------+
| summary |
+-------------------------+
| Inserted 1000000 row(s) |
+-------------------------+
Returned 1 row(s) in 6.32s
对于任何类型的性能实验,使用EXPLAIN语句来查看如何在不实际运行的情况下执行任何昂贵的查询,并启用包含更多面向性能的详细信息的详细EXPLAIN计划:最有趣的计划行以粗体突出显示,表明没有 对于连接表的统计信息,Impala无法很好地估计每个处理阶段涉及的行数,并且可能会坚持使用BROADCAST连接机制将其中一个表的完整副本发送到每个节点。
[localhost:21000] > set explain_level=verbose;
EXPLAIN_LEVEL set to verbose
[localhost:21000] > explain select count(*) from big join medium where
big.id = medium.id;
收集所有表的统计信息非常简单,每个表一个COMPUTE STATS语句:
[localhost:21000] > compute stats small;
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 3 column(s). |
+-----------------------------------------+
Returned 1 row(s) in 4.26s
[localhost:21000] > compute stats medium;
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 5 column(s). |
+-----------------------------------------+
Returned 1 row(s) in 42.11s
[localhost:21000] > compute stats big;
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 5 column(s). |
+-----------------------------------------+
Returned 1 row(s) in 165.44s
有了统计信息,Impala可以选择更有效的连接顺序,而不是遵循查询中从左到右的表序列,并可以根据表中的总体大小和行数选择BROADCAST或PARTITIONED连接策略:
[localhost:21000] > explain select count(*) from medium join big where
big.id = medium.id;
Query: explain select count(*) from medium join big where big.id = medium.id
+-----------------------------------------------------------+
| Explain String |
+-----------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=937.23MB VCores=2 |
当实际运行这些查询时,无论查询文本中的表顺序如何,执行时间都相对一致。 以下是使用唯一ID列和包含重复值的VAL列的示例:
[localhost:21000] > select count(*) from big join small on (big.id =
small.id);
Query: select count(*) from big join small on (big.id = small.id)
+----------+
| count(*) |
+----------+
| 1000000 |
+----------+
Returned 1 row(s) in 21.68s
[localhost:21000] > select count(*) from small join big on (big.id =
small.id);
Query: select count(*) from small join big on (big.id = small.id)
+----------+
| count(*) |
+----------+
| 1000000 |
+----------+
Returned 1 row(s) in 20.45s
[localhost:21000] > select count(*) from big join small on (big.val =
small.val);
+------------+
| count(*) |
+------------+
| 2000948962 |
+------------+
Returned 1 row(s) in 108.85s
[localhost:21000] > select count(*) from small join big on (big.val =
small.val);
+------------+
| count(*) |
+------------+
| 2000948962 |
+------------+
Returned 1 row(s) in 100.76s
注意:在检查连接查询的性能和连接顺序优化的有效性时,请确保查询涉及足够的数据和群集资源,以根据查询计划查看差异。例如,只有几兆字节的单个数据文件将驻留在单个HDFS块中,并在单个节点上进行处理。同样,如果您使用单节点或双节点群集,则广播或分区连接策略的效率可能没有太大差异。
当Impala可以访问有关数据量和值分布方式的统计信息时,它可以对复杂或多表查询进行更好的优化。 Impala使用此信息来帮助并行化和分发工作
查询。例如,优化连接查询需要一种方法来确定一个表是否比另一个表“更大”,这是每个表的行数和平均行大小的函数。以下部分描述了Impala可以使用的统计类别,以及如何生成它们并使它们保持最新。
Impala查询计划程序可以使用有关整个表和分区的统计信息。此信息包括物理特征,例如行数,数据文件数,数据文件的总大小以及文件格式。对于分区表,每个分区计算数字,并计算整个表的总数。此元数据存储在Metastore数据库中,可以通过Impala或Hive进行更新。如果数字不可用,则值-1用作占位符。某些数字(例如数据文件的数量和总大小)始终保持最新,因为它们可以廉价计算,作为收集HDFS块元数据的一部分。
以下示例显示未分区的Parquet表的表统计信息。文件的数量和大小的值始终可用。最初,行数是未知的,因为它需要在整个表中进行可能昂贵的扫描,因此该值显示为-1。 COMPUTE STATS语句填写任何未知的内容
表统计值。
show table stats parquet_snappy;
+-------+--------+---------+--------------+-------------------+---------
+-------------------+...
| #Rows | #Files | Size | Bytes Cached | Cache Replication | Format |
Incremental stats |...
+-------+--------+---------+--------------+-------------------+---------
+-------------------+...
| -1 | 96 | 23.35GB | NOT CACHED | NOT CACHED | PARQUET |
false |...
+-------+--------+---------+--------------+-------------------+---------
+-------------------+...
compute stats parquet_snappy;
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 6 column(s). |
+-----------------------------------------+
show table stats parquet_snappy;
+------------+--------+---------+--------------+-------------------
+---------+-------------------+...
| #Rows | #Files | Size | Bytes Cached | Cache Replication | Format
| Incremental stats |...
+------------+--------+---------+--------------+-------------------
+---------+-------------------+...
| 1000000000 | 96 | 23.35GB | NOT CACHED | NOT CACHED | PARQUET
| false |...
+------------+--------+---------+--------------+-------------------
+---------+-------------------+...
Impala通过使用此元数据自行执行一些优化,并通过使用表和列统计信息的组合执行其他优化。
要检查表的统计信息是否可用,并查看这些统计信息的详细信息,请使用语句SHOW TABLE STATS table_name。有关详细信息,请参见第380页的SHOW语句。
如果您使用基于Hive的收集统计信息的方法,请参阅Hive wiki以获取有关Hive端所需配置的信息。在可行的情况下,请使用Impala COMPUTE STATS语句来避免统计信息收集过程中的潜在配置和可伸缩性问题。
如果运行Hive语句ANALYZE TABLE COMPUTE STATISTICS FOR COLUMNS,则Impala只能在未分区的情况下使用生成的列统计信息。 Impala无法为分区表使用Hive生成的列统计信息。
当元数据在Metastore数据库中可用时,Impala查询计划程序可以使用有关各个列的统计信息。对于在连接查询中的表之间进行比较的列,此技术最有价值,以帮助估计查询将从每个表中检索的行数。这些统计信息对于使用EXISTS()或IN()运算符的相关子查询也很重要,这些运算符的内部处理方式与连接查询相同。
以下示例显示未分区的Parquet表的列统计信息。 某些类型的最大和平均大小的值始终可用,因为这些数字对于数字和其他固定大小类型是常量。 最初,不同值的数量是未知的,因为它需要在整个表中进行可能昂贵的扫描,因此该值显示为-1。 这同样适用于可变大小类型的最大和平均大小,例如STRING。COMPUTE STATS语句填充大多数未知列统计值。 (它不是记录NULL值的数量,因为当前Impala不使用该数字进行查询优化。)
show column stats parquet_snappy;
+-------------+----------+------------------+--------+----------+----------+
| Column | Type | #Distinct Values | #Nulls | Max Size | Avg Size |
+-------------+----------+------------------+--------+----------+----------+
compute stats parquet_snappy;
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 6 column(s). |
+-----------------------------------------+
当您使用Impala作为“大数据”时,您极有可能对最大的表使用分区,表示可以根据日期,地理区域或类似标准进行逻辑划分的数据。表和列统计信息对于优化此类表上的查询特别有用。例如,涉及一年的查询可能涉及比涉及不同年份或几年范围的查询更多或更少的数据。结果可能会对每个查询进行不同的优化。
以下示例显示了表和列统计信息如何与分区表一起使用。此示例的表按年,月和日划分。为简单起见,样本数据由5个分区组成,所有分区都来自同一年和月。为每个分区独立收集表统计信息。 (实际上,SHOW PARTITIONS语句显示与分区表的SHOW TABLE STATS完全相同的信息。)列统计信息适用于整个表,而不是单个分区。由于分区键列值表示为HDFS目录,因此即使非键列的值显示为-1,它们的特性通常也是预先知道的。
show partitions year_month_day;
如果运行Hive语句ANALYZE TABLE COMPUTE STATISTICS FOR COLUMNS,则Impala只能在未分区的情况下使用生成的列统计信息。 Impala无法为分区表使用Hive生成的列统计信息。
使用COMPUTE STATS系列命令收集表和列统计信息。 COMPUTE STATS变体在计算成本,陈旧性和维护工作流程之间提供不同的权衡,这将在下面解释。
重要:
对于特定表,请使用COMPUTE STATS或COMPUTE INCREMENTAL STATS,但绝不要将它们组合在一起或在它们之间交替使用。 如果在表的生存期内从COMPUTE STATS切换到COMPUTE INCREMENTAL STATS,反之亦然,请在进行切换之前通过运行DROP STATS来删除所有统计信息。
COMPUTE STATS
COMPUTE STATS命令收集和设置表级和分区级行计数以及给定表的所有列统计信息。 收集过程是CPU密集型的,对于非常大的表可能需要很长时间才能完成。
在Impala 2.1.0及更高版本中,您可以使用COMPUTE INCREMENTAL STATS和DROP INCREMENTAL STATS命令。 INCREMENTAL子句使用增量统计,这是分区表的专用功能。
在计算分区表的增量统计信息时,默认情况下,Impala仅处理那些尚未具有增量统计信息的分区。 通过仅处理新添加的分区,您可以使统计信息保持最新,而不会产生每次重新处理整个表的开销。
您还可以通过在COMPUTE INCREMENTAL STATS或DROP INCREMENTAL STATS语句中包含PARTITION子句来计算或删除指定分区子集的统计信息。
在Impala 3.0及更低版本中,缓存需要每个分区大约400字节的元数据。 具有大量分区和多列的表可能会增加大量内存开销,因为元数据必须缓存在目录主机和每个有资格成为协调器的impalad主机上。 如果所有表的元数据超过2 GB,则可能会遇到服务停机时间。 在Impala 3.1及更高版本中,通过改进增量统计数据的处理缓解了该问题。
当您第一次在表上运行COMPUTE INCREMENTAL STATS时,无论表是否已有统计信息,都会从头开始重新计算统计信息。 因此,在给定表上第一次运行COMPUTE INCREMENTAL STATS时,期望一次性资源密集型操作来扫描整个表。
您可以使用SHOW TABLE STATS语句(对于任何表)或SHOW PARTITIONS语句(对于分区表)检查特定表是否具有统计信息。 两个语句都显示相同的信息。 如果表或分区没有任何统计信息,则#Rows字段包含-1。 计算表或分区的统计信息后,#Row字段将更改为准确值。
以下示例显示了最初没有任何统计信息的表。 SHOW TABLE STATS语句在COMPUTE STATS操作之前和之后显示#Rows的不同值。
[localhost:21000] > create table no_stats (x int);
[localhost:21000] > show table stats no_stats;
+-------+--------+------+--------------+--------+-------------------+
| #Rows | #Files | Size | Bytes Cached | Format | Incremental stats |
+-------+--------+------+--------------+--------+-------------------+
| -1 | 0 | 0B | NOT CACHED | TEXT | false |
+-------+--------+------+--------------+--------+-------------------+
[localhost:21000] > compute stats no_stats;
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 1 column(s). |
+-----------------------------------------+
[localhost:21000] > show table stats no_stats;
+-------+--------+------+--------------+--------+-------------------+
| #Rows | #Files | Size | Bytes Cached | Format | Incremental stats |
+-------+--------+------+--------------+--------+-------------------+
| 0 | 0 | 0B | NOT CACHED | TEXT | false |
+-------+--------+------+--------------+--------+-------------------+
以下示例显示了与分区表类似的进程。 最初,#Row是-1。 在COMPUTE STATS操作之后,#Lines会更改为准确值。 任何新添加的分区都没有统计信息,这意味着您必须在添加新分区后收集统计信息。
[localhost:21000] > create table no_stats_partitioned (x int) partitioned by
(year smallint);
[localhost:21000] > show table stats no_stats_partitioned;
由于Impala与其他Hadoop组件一样,旨在处理分布式环境中的大量数据,因此请使用实际数据和群集配置进行任何性能测试。 使用多节点群集而不是单个节点; 对包含数TB数据而不是数十GB数据的表运行查询。 Impala使用的并行处理技术最适合超出单个服务器容量的工作负载。
当您运行返回大量行的查询时,相当于打印输出的CPU时间可能会很长,从而导致实际查询时间的测量值不准确。 考虑在impala-shell命令上使用-B选项来关闭漂亮打印,并且可选地使用-o选项将查询结果存储在文件中而不是打印到屏幕上。
有时,将原始查询性能与可伸缩性进行平衡需要限制单个查询或查询组使用的资源(如内存或CPU)的数量。 Impala可以使用多种机制来帮助在大量并发使用期间消除负载,从而加快整个查询时间,并跨群集中的Impala查询,MapReduce作业和其他类型的工作负载共享资源:
Impala许可控制功能使用快速的分布式机制来阻止超过并发查询数或使用的内存量限制的查询。查询排队,并在其他查询完成且资源可用时执行。您可以控制并发限制,并为不同的用户组指定不同的限制,以根据不同用户类的优先级划分群集资源。此功能是Impala 1.3中的新功能。有关详细信息,请参阅第682页的“准入控制和查询队列”。
您可以通过为impalad守护程序指定-mem_limit选项来限制Impala在查询执行期间保留的内存量。有关详细信息,请参阅第33页的修改Impala启动选项。这个限制仅适用于查询直接使用的内存; Impala在启动时保留额外的内存,例如用于保存缓存的元数据。
对于生产部署,请使用群集管理工具实施资源隔离。
运行时过滤是Impala 2.5及更高版本中提供的广泛优化功能。 当针对分区表的查询仅需要表中的一小部分数据或评估连接条件时,Impala在查询运行时确定适当的条件,并将该信息广播到正在读取的所有impalad节点 表,以便它们可以避免不必要的I / O读取分区数据,并通过仅发送与网络中的连接键匹配的行子集来避免不必要的网络传输。
在计划片段之间传输的过滤器实质上是连接键列的值列表。当这个值列表及时传输到扫描节点时,Impala可以在读取后立即过滤掉不匹配的值,而不是将原始数据传输到另一个主机以与该主机上的内存中哈希表进行比较。
对于基于HDFS的表,此数据结构实现为Bloom过滤器,该过滤器使用基于概率的算法来确定所有可能的匹配值。 (基于概率的方面意味着过滤器可能包含一些不匹配的值,但如果是这样,则不会导致最终结果出现任何不准确。)
另一种过滤器是“最小 - 最大”过滤器。它目前仅适用于Kudu表。过滤器是表示最小值和最大值的数据结构。这些过滤器将传递给Kudu,以减少在扫描连接的探测器侧时返回到Impala的行数。
有不同种类的过滤器可以匹配不同类型的连接(分区和广播)。广播过滤器反映相关值的完整列表,并且可以由扫描节点立即评估。分区筛选器仅反映群集中一个主机处理的值;在扫描节点可以使用结果准确过滤从存储中读取的数据之前,必须将所有分区过滤器合并为一个(由协调器节点)。
广播过滤器也被分类为本地或全局。使用本地广播过滤器,过滤器中的信息由后续查询片段使用,该后续查询片段在生成过滤器的同一主机上运行。必须通过网络将非本地广播过滤器传输到在不同主机上运行的查询片段。 Impala指定3个主机,每个主机产生非本地广播过滤器,以防止单个慢速主机花费太长时间。根据RUNTIME_FILTER_MODE查询选项(LOCAL或GLOBAL)的设置,Impala要么使用一种保守的优化策略,其中过滤器仅在生成它们的同一主机上使用,或者是一种更积极的策略,其中过滤器有资格通过网络传输。
注意:在Impala 2.6及更高版本中,运行时筛选的缺省值是GLOBAL设置。
Parquet表从运行时筛选优化中获得最大收益。运行时筛选可以加快针对分区或未分区Parquet表的连接查询,以及针对分区Parquet表的单表查询。
对于其他文件格式(文本,Avro,RCFile和SequenceFile),运行时筛选仅针对分区表加速查询。由于分区表可以使用多种格式,因此Impala会在所有情况下生成过滤器,即使它们最终未用于优化查询。
因为生成运行时过滤器需要时间,特别是对于必须由协调器节点组合的分区过滤器,所以有一个时间间隔,超过该时间间隔,扫描节点继续构建其中间结果集会更有效,即使这样中间数据大于最优。如果生成过滤器只需要几秒钟,那么如果修剪不必要的数据可以在整个查询时间内节省几分钟,那么值得花费额外的时间。您可以使用RUNTIME_FILTER_WAIT_TIME_MS查询选项指定最长等待时间(以毫秒为单位)。
默认情况下,每个扫描节点等待最多1秒(1000毫秒)的过滤器到达。如果所有过滤器都未在指定的时间间隔内到达,则扫描节点继续使用所到达的任何过滤器以帮助避免读取不必要的数据。如果在扫描节点开始读取数据后过滤器到达,则扫描节点将该过滤器应用于过滤器到达后读取的数据,但不应用于已读取的数据。
如果群集相对繁忙且您的工作负载包含许多资源密集型或长时间运行的查询,请考虑增加等待时间,以便复杂查询不会错过优化机会。如果群集负载较轻且您的工作负载包含许多只需几秒钟的小查询,请考虑减少等待时间以避免每次查询延迟1秒。
同样,EXPLAIN语句显示的查询计划包含有关谓词的信息每个计划片段使用它,它还包括显示计划片段是否产生或消耗的注释运行时过滤器。 生成过滤器的计划片段包括注释,例如运行时过滤器:filter_id < - table.column,而使用过滤器的计划片段包括注释,例如运行时过滤器:filter_id - > table.column。 设置查询选项EXPLAIN_LEVEL = 2会添加显示过滤器类型的其他注释,filter_id [bloom](对于基于HDFS的表)或filter_id [min_max](对于Kudu表)。
以下示例显示了一个查询,该查询使用标记为RF000的单个运行时筛选器基于在运行时评估子查询的结果集来修剪分区:
CREATE TABLE yy (s STRING) PARTITIONED BY (year INT);
INSERT INTO yy PARTITION (year) VALUES ('1999', 1999), ('2000', 2000),('2001', 2001), ('2010', 2010), ('2018', 2018);
COMPUTE STATS yy;
CREATE TABLE yy2 (s STRING, year INT);
INSERT INTO yy2 VALUES ('1999', 1999), ('2000', 2000), ('2001', 2001);
COMPUTE STATS yy2;
EXPLAIN SELECT s FROM yy WHERE year IN (SELECT year FROM yy2);
[slave1:21000] default> EXPLAIN SELECT s FROM yy WHERE year IN (SELECT year FROM yy2);
Query: EXPLAIN SELECT s FROM yy WHERE year IN (SELECT year FROM yy2)
+--------------------------------------------------+
| Explain String |
+--------------------------------------------------+
| Max Per-Host Resource Reservation: Memory=2.94MB |
| Per-Host Resource Estimates: Memory=82.94MB |
| Codegen disabled by planner |
| |
| PLAN-ROOT SINK |
| | |
| 04:EXCHANGE [UNPARTITIONED] |
| | |
| 02:HASH JOIN [LEFT SEMI JOIN, BROADCAST] |
| | hash predicates: year = year |
| | runtime filters: RF000 <- year |
| | |
| |--03:EXCHANGE [BROADCAST] |
| | | |
| | 01:SCAN HDFS [default.yy2] |
| | partitions=1/1 files=1 size=30B |
| | |
| 00:SCAN HDFS [default.yy] |
| partitions=5/5 files=5 size=25B |
| runtime filters: RF000 -> year |
+--------------------------------------------------+
在此示例中,在根据从所有TINY_T2.ID值构造的内存中哈希表检查ID值之前,Impala通常会执行额外的工作来解释HUGE_T1中每行的列C1,C2,C3和ID。通过在查询开始扫描HUGE_T1表之前生成包含所有TINY_T2.ID值的过滤器,Impala可以跳过不必要的工作来解析列信息,只要它确定ID值与来自该值的任何值都不匹配。其他表。
该示例显示了两个表的COMPUTE STATS语句(即使这是在将数据加载到这些表之后的一次性操作),因为Impala依赖于最新的统计信息来确定哪个具有比另一个更多的不同ID值。该信息使Impala能够有效地决定使用哪个表来构造内存中的哈希表,以及从磁盘读取哪个表并与哈希表中的条目进行比较。
COMPUTE STATS huge_t1;
COMPUTE STATS tiny_t2;
SELECT c1, c2, c3 FROM huge_t1 JOIN tiny_t2 WHERE huge_t1.id = tiny_t2.id;
在此示例中,T1是按年份分区的表。 T2上的子查询产生多个值,并将这些值作为过滤器传输到从T1读取的计划片段。 跳过T1中的任何不匹配分区。
select c1 from t1 where year in (select distinct year from t2);
现在,WHERE子句包含一个不适用于分区键列的附加测试。 不是分区键的列上的过滤器称为每行过滤器。 由于每行过滤器仅适用于Parquet,因此T1必须是Parquet表。
子查询导致两个过滤器被传输到从T1读取的扫描节点。 YEAR上的过滤器可帮助查询根据不匹配的年份消除整个分区。 C2上的过滤器允许Impala在读取后立即丢弃具有不匹配C2值的行。 如果没有运行时过滤,Impala必须将非匹配值保留在内存中,将C1,C2和C3组合成中间结果集中的行,并将所有中间行传回给协调器节点,在那里它们只会被消除 在查询的最后。
select c1, c2, c3 from t1
where year in (select distinct year from t2)
and c2 in (select other_column from t3);
此示例涉及广播连接。 ON子句将返回少量匹配行的事实(因为TINY_T2中的行数不是很多)意味着相应的过滤器非常有选择性。 因此,运行时筛选可能会有效地优化此查询。
select c1 from huge_t1 join [broadcast] tiny_t2
on huge_t1.id = tiny_t2.id
where huge_t1.year in (select distinct year from tiny_t2)
and c2 in (select other_column from t3);
此示例涉及shuffle或分区连接。 假设HUGE_T1中的大多数行在HUGE_T2中都有对应的行。 ON子句可以返回大量匹配行的事实意味着相应的过滤器不会非常有选择性。 因此,运行时筛选在优化此查询时可能效果较差。
select c1 from huge_t1 join [shuffle] huge_t2
on huge_t1.id = huge_t2.id
where huge_t1.year in (select distinct year from huge_t2)
and c2 in (select other_column from t3);
这些调优和故障排除过程适用于资源密集程度足够长,运行时间足够长且足够频繁的查询,您可以特别注意单独优化它们。
使用EXPLAIN语句并检查运行时过滤器:行以确定是否将运行时过滤器应用于您期望的WHERE谓词和连接子句。例如,由于非等值连接运算符,运行时筛选不适用于使用嵌套循环连接机制的查询。
确保查询中涉及的所有表的统计信息都是最新的。将数据加载到非分区表后使用COMPUTE STATS语句,并在将新分区添加到分区表后使用COMPUTE INCREMENTAL STATS。
如果涉及大型表的连接查询使用唯一列作为连接键,例如将主键列与外键列连接,则生成和传输过滤器的开销可能超过性能优势,因为在早期可能无法修剪太多数据查询的各个阶段。对于此类查询,请考虑设置查询选项RUNTIME_FILTER_MODE = OFF。
运行时筛选功能对Parquet文件格式最有效。对于其他文件格式,过滤仅适用于分区表。请参阅运行时筛选的文件格式注意事项(第654页)。有关运行时筛选对Kudu表的工作方式,请参阅Kuala表的Impala查询性能(第707页)。
在查询期间在特定主机上激活溢出到磁盘机制时,该主机在处理该查询时不会生成任何过滤器。此限制不会影响结果的正确性;它只会减少可应用于查询的优化量。
HDFS缓存在生产环境中提供了性能和可扩展性优势,其中Impala查询和其他Hadoop作业的操作数据量远大于DataNode上的物理RAM,这使得依赖Linux OS缓存变得不切实际,因为它只保留最近使用的内存中的数据。从HDFS缓存读取的数据避免了在使用来自Linux OS缓存的数据时所涉及的校验和和内存到内存复制的开销。
注意:在小型或轻载的群集上,HDFS缓存可能不会产生任何加速。如果在整个集群中并行执行的I / O读取操作被在少量主机上运行的内存中操作所取代,则甚至可能导致查询速度变慢。缓存HDFS块的主机可能成为瓶颈,因为它们在处理缓存的数据块时遇到高CPU负载,而其他主机保持空闲状态。因此,使用实际工作负载时,始终使用和不启用此功能来比较性能。
在Impala 1.4及更高版本中,Impala可以使用HDFS缓存功能更有效地使用RAM,因此重复查询可以利用内存中“固定”的数据,无论总体处理多少数据。 HDFS缓存功能允许您将经常访问的数据的子集指定为永久固定在内存中,保留在多个查询的缓存中,并且永远不会被驱逐。此技术适用于经常访问且足够小以完全适合HDFS内存高速缓存的表或分区。例如,您可以指定要在缓存中固定的多个维度表,以加速引用它们的许多不同的连接查询。或者在分区表中,您可以固定一个分区来保存最近一段时间内的数据,因为这些数据将被集中查询;然后,当下一组数据到达时,您可以取消固定前一个分区并固定包含新数据的分区。
由于此Impala性能功能依赖于HDFS基础结构,因此它仅适用于使用HDFS数据文件的Impala表。 Impala的HDFS缓存不适用于HBase表,S3表,Kudu表或Isilon表。
要在Impala中使用HDFS缓存,请首先为群集设置该功能:
确定每台主机上用于HDFS缓存的内存量。请记住,缓存数据的可用内存总量是所有主机上缓存大小的总和。默认情况下,任何数据块仅缓存在一个主机上,但您可以通过增加复制因子来跨多个主机缓存块。
发出hdfs cacheadmin命令以设置一个或多个缓存池,这些缓存池由与impalad守护程序相同的用户拥有(通常为impala)。例如:
hdfs cacheadmin -addPool four_gig_pool -owner impala -limit 4000000000
启用HDFS缓存并且有一个或多个池可用后,请参阅为Impala表和分区启用HDFS缓存(第658页),了解如何选择要加载到HDFS缓存中的Impala数据。 关于Impala,您可以在Impala DDL语句中指定由hdfs cacheadmin命令定义的缓存池名称,以便为表或分区启用HDFS缓存,例如CREATE TABLE … CACHED IN pool或ALTER TABLE … SET CACHED IN pool。
首先选择要缓存的表或分区。 例如,这些可能是由许多不同的连接查询访问的查找表,或者是由不同报告或即席查询分析的最近时间段对应的分区。
在您的SQL语句中,您指定要缓存的逻辑分区,例如表和分区。 Impala将这些请求转换为适用于特定目录和文件的HDFS级指令。 例如,给定具有分区键列YEAR的分区表CENSUS,您可以选择缓存全部或部分数据,如下所示:
在Impala 2.2及更高版本中,CREATE TABLE和ALTER TABLE的可选WITH REPLICATION子句允许您指定复制因子,即缓存相同数据块的主机数。 当Impala处理高速缓存复制因子大于1的高速缓存数据块时,Impala会随机选择具有该数据块的高速缓存副本的主机。 当多次处理相同的缓存数据块时,此优化可避免单个主机上过多的CPU使用率。 在可行的情况下,指定大于或等于HDFS块复制因子的值。
-- Cache the entire table (all partitions). alter table census set cached in 'pool_name';
-- Remove the entire table from the cache.
alter table census set uncached;
-- Cache a portion of the table (a single partition).
-- If the table is partitioned by multiple columns (such as year, month,
day),
-- the ALTER TABLE command must specify values for all those columns. alter table census partition (year=1960) set cached in 'pool_name';
-- Cache the data from one partition on up to 4 hosts, to minimize CPU load
on any
-- single host when the same data block is processed multiple times.
alter table census partition (year=1970)
set cached in 'pool_name' with replication = 4;
-- At each stage, check the volume of cached data.
-- For large tables or partitions, the background loading might take some
time,
-- so you might have to wait and reissue the statement until all the data
-- has finished being loaded into the cache.
show table stats census;
CREATE TABLE注意事项:
HDFS缓存功能会影响Impala CREATE TABLE语句,如下所示:
其他内存考虑:
当底层HDFS目录包含缓存文件时,某些DDL操作(例如ALTER TABLE … SET LOCATION)将被阻止。您必须先删除文件,然后才能更改位置,删除表格,等等。
当请求将数据固定在内存中时,该进程在后台发生,而不会在缓存进行时阻止对数据的访问。从磁盘加载数据可能需要一些时间。如果已经固定,Impala会从内存中读取每个HDFS数据块,如果尚未固定,则从磁盘读取。
您可以通过HDFS缓存机制在每个节点上固定的数据量受基础HDFS服务强制实施的配额限制。在请求在内存中固定Impala表或分区之前,请检查其大小是否超过此配额。
注意:由于HDFS缓存由来自群集中所有DataNode的组合内存组成,因此缓存的表或分区可能大于任何单个主机上的HDFS缓存内存量。
启用HDFS缓存后,当您通过INSERT和DROP TABLE等语句添加或删除数据时,后台会进行额外处理。
插入或加载数据:
删除表,分区或缓存池:
HDFS缓存功能与Impala DROP TABLE和ALTER TABLE … DROP PARTITION语句交互,如下所示:
为完全缓存的表发出DROP TABLE或缓存某些分区时,DROP TABLE成功,并且从HDFS缓存系统中删除为该表提交的所有缓存指令Impala。
这同样适用于ALTER TABLE … DROP PARTITION。操作成功,并删除任何缓存指令。
与往常一样,如果删除的表是内部表,则删除基础数据文件,或者删除的分区位于内部表下的默认位置。如果删除的表是外部表,或者删除的分区位于非默认位置,则数据文件将保持不变。
如果通过hdfs cacheadmin命令将数据文件指定为缓存,并且数据文件如上一项所述留下,则数据文件将保持缓存状态。 Impala仅通过CREATE TABLE或ALTER TABLE语句删除Impala提交的缓存指令。可以有多个与相同文件有关的冗余缓存指令;这些指令都有唯一的ID和所有者,因此系统可以区分它们。
如果通过hdfs cacheadmin命令删除HDFS缓存池,则会保留所有Impala数据文件,不再缓存。在后续REFRESH之后,SHOW TABLE STATS报告为每个关联的Impala表或分区缓存0个字节。
重新定位表或分区:
HDFS缓存功能与Impala ALTER TABLE … SET LOCATION语句交互,如下所示:
以下是检查或更改Impala数据的HDFS缓存状态的准则和步骤:
hdfs cacheadmin命令:
hdfs cacheadmin -listDirectives # Basic info
hdfs cacheadmin -listDirectives -stats # More details
Impala SHOW 语句:
Impala HDFS缓存功能与Impala内存限制交互,如下所示:
在Impala 1.4.0及更高版本中,Impala支持通过HDFS缓存固定在内存中的数据的高效读取。 Impala利用HDFS API并从内存而不是从磁盘读取数据,无论数据文件是使用Impala DDL语句固定,还是使用指定HDFS路径的命令行机制。
检查impala-shell SUMMARY命令的输出,或查看impalad守护程序的度量报告时,可以看到从HDFS缓存中读取了多少字节。 例如,查询配置文件中的这段摘录说明在查询的特定阶段读取的所有数据都来自HDFS缓存,因为BytesRead和BytesReadDataNodeCache值是相同的。
对于涉及较少数据量或单用户工作负载的查询,您可能不会注意到有或没有HDFS缓存的查询响应时间的显着差异。即使关闭了HDFS缓存,查询的数据仍可能位于Linux OS缓冲区缓存中。随着数据量的增加,优势变得更加清晰,尤其是在系统处理更多并发查询时。 HDFS缓存提高了整个系统的可扩展性。也就是说,当工作负载超过Linux OS缓存容量时,它会阻止查询性能下降。
由于HDFS的限制,加密不支持零拷贝读取。在可行的情况下,请避免对加密区域中的Impala数据文件进行HDFS缓存。在查询执行期间,查询会回退到正常的读取路径,这可能会导致一些性能开销。
SELECT注意事项:
Impala HDFS缓存功能与SELECT语句和查询性能交互,如下所示:
$ sync
$ echo 1 > /proc/sys/vm/drop_caches
测试以确保Impala配置为获得最佳性能。如果已使用群集管理软件安装Impala,请完成本主题中描述的过程以帮助确保正确配置。这些过程可用于验证Impala是否已正确设置。
检查Impala配置值
您可以使用浏览器连接到Impala服务器来检查Impala配置值。
要检查Impala配置值:
要检查数据位置:
[impalad-host:21000] > SELECT COUNT (*) FROM MyTable
Total remote scan volume = 0
远程扫描的存在可能表示impalad未在正确的节点上运行。这可能是因为某些DataNode没有运行impalad,或者可能是因为启动查询的impalad实例无法联系一个或多个impalad实例。
要了解此问题的原因:
查看Impala日志
您可以查看Impala日志的内容,以查找短路读取或阻止位置跟踪不起作用的迹象。在检查日志之前,对小型HDFS数据集执行简单查询。完成查询任务使用当前设置生成日志消息。有关启动Impala和执行查询的信息,请参阅第32页的启动Impala和第614页的使用Impala Shell(impala-shell命令)。有关日志记录的信息,请参阅使用Impala日志记录(第780页)。日志消息及其解释如下面所述:
Unknown disk id. This will negatively affect performance. Check your hdfs settings to enable block
location metadata => Tracking block locality is not enabled.
Unable to load native-hadoop library for your platform... using builtin-java classes where applicable => Native checksumming is not enabled.
要了解Impala查询的高级性能注意事项,请阅读查询的EXPLAIN语句的输出。您可以在不实际运行查询的情况下获取EXPLAIN计划。
有关查询的物理性能特征的概述,请在执行查询后立即在impalahell中发出SUMMARY语句。此压缩信息显示执行的哪些阶段占用时间最多,以及每个阶段的内存使用量和行数估计值与实际值的比较情况。
要了解查询的详细性能特征,请在执行查询后立即在impala- shell中发出PROFILE语句。此低级别信息包括有关内存,CPU,I / O和网络使用情况的物理详细信息,因此仅在实际运行查询后才可用。
另请参阅针对Impala-HBase集成的性能注意事项(第707页)和了解和调优S3数据的Impala查询性能(第769页),以获取解释针对HBase表和存储在Amazon Simple Storage System(S3)中的数据的查询的EXPLAIN计划的示例。
EXPLAIN语句概述了查询将执行的逻辑步骤,例如如何在节点之间分配工作以及如何组合中间结果以生成最终结果集。您可以在实际运行查询之前查看这些详细信息。您可以使用此信息来检查查询是否会以某种非常意外或低效的方式运行。
[impalad-host:21000] > EXPLAIN SELECT COUNT(*) FROM customer_address;
EXPLAIN计划也打印在使用查询配置文件进行性能调优(第666页)中所述的查询配置文件报告的开头,以便于并排检查查询的逻辑和物理方面。
EXPLAIN输出中显示的详细信息量由EXPLAIN_LEVEL查询选项控制。在性能调整期间或在与资源管理功能一起估计查询资源使用情况时,双重检查表和列统计信息的存在时,通常会将此设置从标准增加到扩展(或从1增加到2)。
impala-shell解释器中的SUMMARY命令为您提供了一个易于理解的概述,用于查询的不同执行阶段的时间。与EXPLAIN计划一样,很容易发现潜在的性能瓶颈。与PROFILE输出一样,它在查询运行后可用,因此显示实际的时序数。
摘要报告也打印在使用查询配置文件进行性能调整(第666页)中所述的查询配置文件报告的开头,以便于并排检查查询的高级和低级方面。
例如,这是一个涉及单个节点VM上的聚合函数的查询。不同的阶段显示查询及其计时(汇总所有节点),以及计划查询时使用的估计值和实际值。在这种情况下,针对每个节点上的数据子集计算AVG()函数(阶段01),然后在结束时(阶段03)组合来自所有节点的聚合结果。您可以看到哪些阶段花费的时间最多,以及任何估算是否与实际数据分布大不相同。 (在检查时间值时,请务必考虑后缀,例如我们的微秒和毫秒,而不是仅查找最大的数字。)
[localhost:21000] > select avg(ss_sales_price) from store_sales where
ss_coupon_amt = 0;
+---------------------+
| avg(ss_sales_price) |
+---------------------+
| 37.80770926328327 |
+---------------------+
[localhost:21000] > summary;
impala语言解释器中提供的PROFILE语句生成详细的低级报告,显示最近的查询是如何执行的。与使用EXPLAIN计划进行性能调整(第664页)中描述的EXPLAIN计划不同,此信息仅在查询完成后可用。它显示了每个节点的物理详细信息,例如读取的字节数,最大内存使用量等。您可以使用此信息来确定查询是I / O绑定还是CPU绑定,某些网络条件是否存在瓶颈,减速是否影响某些节点而不影响其他节点,以及检查建议的配置设置(如短路本地读取有效。
默认情况下,配置文件输出中的时间值反映操作所需的挂钟时间。对于表示系统时间或用户时间的值,测量单位反映在度量标准名称中,例如ScannerThreadsSysTime或ScannerThreadsUserTime。例如,多线程I / O操作可能会显示挂钟时间的小数字,而相应的系统时间则更大,表示每个线程占用的CPU时间总和。或者挂钟时间数字可能更大,因为它计算等待的时间,而相应的系统和用户时间数字仅测量操作积极使用CPU周期时的时间。
EXPLAIN计划也会在查询配置文件报告的开头打印,以方便同时检查查询的逻辑和物理方面。 EXPLAIN_LEVEL查询选项还控制PROFILE命令打印的EXPLAIN输出的详细程度。
在Impala 3.2中,新的“每节点配置文件”部分已添加到配置文件输出中。新部分包括可由RESOURCE_TRACE_RATIO查询选项控制的以下度量标准。主机CPU使用率指标(用户,系统和IO等待时间)已在该部分中。
为了获得Impala并行查询的最佳性能,工作在群集中的主机之间平均分配,并且所有主机花费大约相等的时间来完成其工作。如果一个主机占用的时间比其他主机长得多,则慢主机所需的额外时间可能成为查询性能的主要因素。因此,Impala性能调优的第一步是检测和纠正这些情况。
可以在Impala中纠正的性能不均匀的主要原因是每个主机处理的HDFS数据块的数量存在偏差,其中一些主机处理的数据块比其他主机多得多。这种情况可能是由于数据值本身的不均匀分布而发生的,例如导致某些数据文件或分区很大而其他数据文件或分区非常小。 (尽管可能会有不均匀分布的数据,而HDFS块的分布没有任何问题。)块偏斜也可能是由于HDFS中的底层块分配策略,数据文件的复制因素以及Impala选择的方式主机处理每个数据块。
检测块偏斜或一般的慢主机问题最方便的方法是在运行查询后检查查询配置文件中的“执行摘要”信息:
对于查询的每个阶段,您会看到平均时间和最大时间值,以及表示该查询阶段涉及的主机数量的#Hosts。对于#Hosts大于1的所有阶段,查找最大时间远远大于平均时间的情况。专注于花费时间最长的阶段,例如,花费多秒而不是毫秒或微秒的阶段。
如果您检测到某些主机比其他主机花费的时间更长,请首先排除非Impala原因。某些主机可能比其他主机慢的一个原因是,如果这些主机的容量低于其他主机,或者由于非Impala工作负载分布不均而导致它们更加繁忙:
如果群集中的主机均匀供电且均匀加载,请检查详细的配置文件输出,以确定哪个主机在查询阶段所花费的时间比其他主机长。检查该主机上该阶段处理的字节数,使用的内存量以及通过网络传输的字节数。
最常见的症状是在一个主机上读取的字节数高于其他主机,因为请求一个主机处理更多数量的HDFS数据块。当查询访问的块数相对较小时,更可能发生这种情况。例如,如果您有一个10节点集群并且查询处理10个HDFS块,则每个节点可能不会处理一个块。如果一个节点处于空闲状态而另一个节点处理两个块,则查询可能需要两倍于数据完全分布的时间。
这种情况下可能的解决方案包括
如果查询人为地较小(可能是出于基准测试目的),请将其扩展为处理更大的数据集。例如,如果某些节点读取10个HDFS数据块而其他节点读取11个,则不均匀分布的总体影响远低于某些节点的工作量是其他节点的两倍。作为指导,针对“最佳点”,每个节点从每个查询的HDFS读取2 GB或更多。处理较低容量的查询可能会遇到性能不一致的情况,随着查询变得更加数据密集而变得平滑。
如果查询仅处理几个大块,以便许多节点处于空闲状态并且无法帮助并行化查询,请考虑减少整体块大小。例如,您可以在将数据复制或转换为Parquet表之前调整PARQUET_FILE_SIZE查询选项。或者,您可以通过非Impala组件调整早期在ETL管道中生成的数据文件的粒度。在Impala 2.0及更高版本中,默认的Parquet块大小为256 MB,从1 GB减少,以改善常见群集大小和数据量的并行性。
减少应用于数据的压缩量。对于文本数据文件,压缩程度最高(gzip)生成不可分割的文件,Impala难以并行处理,并且在处理过程中需要额外的内存来同时保存压缩和未压缩的数据。对于Parquet和Avro等二进制格式,压缩可以减少整体数据块,但请记住,当查询处理相对较少的块时,并行执行的机会较少,并且群集中的许多节点可能处于空闲状态。请注意,当Impala使用查询选项COMPRESSION_CODEC = NONE启用Parquet数据时,由于Parquet使用的编码方案,数据仍然通常是紧凑的,与最终压缩步骤无关。