Impala 性能調整(翻譯)

Impala 性能調整

下面的章節介紹影響 Impala 功能性能的各類因素,並對 Impala 查詢和其餘 SQL 操做進行性能調整、監控和基準測試。 html

這一章節一樣描述了最大化 Impala 可擴展性的技術。可擴展性與性能相關:它意味着當系統負載增長時仍保持高性能(Scalability is tied to performance: it means that performance remains high as the system workload increases)。例如,減小查詢的硬盤 I/O 能夠加快單個的查詢,與此同時,致使能夠同時運行更多查詢,從而提高了可擴展性。有時候,一種優化技術提高了性能的同時更增長了可擴展性。例如,減小查詢的內存使用可能不會很大的提升查詢性能,可是經過容許同時運行更多的 Impala 查詢或其餘類型的做業而不會耗盡內存,從而提高了可擴展性。 java

  Note:

在開始任何性能調整和基準測試以前,請確保你的系統已經按照 Post-Installation Configuration for Impala 中的設置進行配置。 node

  • Partitioning. 這一技術基於頻繁查詢的列上的不一樣的值,把數據物理拆分開來,容許查詢跳過讀取表中很大部分的數據
  • Performance Considerations for Join Queries. 相對於修改物理因素,如文件格式或硬件配置,鏈接是你能夠在 SQL 層級進行調整的主要方面(Joins are the main class of queries that you can tune at the SQL level, as opposed to changing physical factors such as the file format or the hardware configuration)。對於鏈接的性能,相關的主題 Column Statistics 和 Table Statistics 一樣重要
  • Table Statistics and Column Statistics. 使用 COMPUTE STATS 語句,採集表和列的統計信息,幫助 Impala 自動優化鏈接查詢的性能,而不須要修改 SQL 查詢語句(在 Impala 1.2.2 及以上版本,這一過程特別簡單,由於 COMPUTE STATS 語句在同一個語句中同時採集兩種信息,並且不須要像以前在 Hive 中運行 ANALYZE TABLE 語句那樣,再也不須要執行任何設置和配置)
  • Testing Impala Performance. 在進行任何基準測試以前,執行一些安裝後測試(post-setup testing),以確保 Impala 使用了性能最優的設置
  • Benchmarking Impala Queries. 用於 Impala 初始實驗的配置和樣本數據一般不適合進行性能測試(The configuration and sample data that you use for initial experiments with Impala is often not appropriate for doing performance tests)
  • Controlling Resource Usage. 更多內存,更加性能(The more memory Impala can utilize, the better query performance you can expect)。在一個一樣運行其餘負載的集羣中,你必須權衡考慮,保證全部 Hadoop 組件具備能良好運行的足夠內存,所以你可能限制 Impala 可以使用的內存

分區

表的全部數據文件默認放在一個目錄下。分區是一項基於一個或多個上的值,在載入時物理拆分數據的技術。例如,對於根據 year 列分區的 school_records 表來講,對於每個不一樣的年份都有一個單獨的數據目錄,而且這一年的全部數據都存放在這個目錄下的數據文件中。一個包含 WHERE 條件如 YEAR=1966, YEAR IN (1989,1999), YEAR BETWEEN 1984 AND 1989 的查詢,能夠只從對應的一個或多個目錄下檢索數據文件,極大的減小了讀取和測試的數據的數量。 web

分區一般對應: sql

  • 很是大的表,完整讀取整個數據集花費的時間不可想象(where reading the entire data set takes an impractical amount of time)
  • 所有或幾乎全部的查詢都包含分區列查詢條件的表。咱們上面的例子中那個根據 year 分區的表, SELECT COUNT(*) FROM school_records WHERE year = 1985 是高效的,只檢索數據的一小部分;可是 SELECT COUNT(*) FROM school_records 則必須處理每年的單獨的數據文件,致使必未分區表更多的工做。假如你頻繁基於 last name, student ID, 等等不檢測年份的對錶進行查詢,考慮不分區表
  • 列包含合理的基數(cardinality--不一樣值的個數)。假如列只包括少許的值,如 Male 或 Female,你沒法經過對每個查詢消除大約 50% 數據的讀取來得到更高的效率。假如列的每個值只對應不多的行,要處理的目錄的數量會變成一個限制因素,而且每個目錄中的數據文件可能過小了,沒法從 Hadoop 以 multi-megabyte 塊傳輸數據的機制受益。例如,你可能用年來分區人口數據,用年和月來存放銷售數據,用年月日來分區網絡流量數據(一些更高流量的用戶甚至用小時和分鐘來分區數據)
  • 老是使用抽取、轉換、加載(ETL)管道加載的數據。分區列的值從原始的數據文件剝離,並對應到目錄名中,所以加載數據到分區表涉及了某種轉換或預處理(The values of the partitioning columns are stripped from the original data files and represented by directory names, so loading data into a partitioned table involves some sort of transformation or preprocessing)

在 Impala SQL 語法中,分區會影響到這些語句: shell

  • CREATE TABLE: 在建立表時,使用 PARTITIONED BY 子句來標識分區列的名稱和數據類型。表中的列不包括這些分區列
  • ALTER TABLE: 能夠添加或刪除分區,用於處理海量數據集的不一樣部分。對於根據日期值分區的數據,你能夠再也不保留"過時(age out)"的數據
  • INSERT: 當向分區表插入數據時,須要標識分區列。對於插入的每一行,分區列的值沒有保存在數據文件裏,而是根據行存儲的目錄名稱肯定。也可使用 INSERT OVERWRITE 語句來加載一組數據到指定的分區;你能夠替換指定分區的內容可是不能向指定分區追加數據
  • 儘管表分區與否的 SELECT 語句的語法相同,對分區表的查詢方式可能對性能和可擴展性產生戲劇性的影響。在查詢過程當中,讓查詢跳過某些分區的機制稱做分區修剪(partition pruning);參見 Partition Pruning for Queries 瞭解詳細信息

參見 Attaching an External Partitioned Table to an HDFS Directory Structure 中的例子,演示了建立分區表的語法,HDFS 中底層的目錄結構,以及如何鏈接到 Impala 外部分區表中存出來 HDFS 其餘位置的數據文件(how to attach a partitioned Impala external table to data files stored elsewhere in HDFS) 數據庫

參見 Partitioning for Parquet Tables 瞭解 Parquet 分區表的性能注意事項。 apache

參見 NULL 瞭解分區表中 NULL 值如何對應。 瀏覽器

針對查詢進行分區修剪(Partition Pruning)

分區修剪(Partition pruning)指的是一種查詢能夠跳過一個或多個分區對應的數據文件不進行讀取的技術。假如你能安排你的查詢從查詢計劃中剪除大量的沒必要要的分區,查詢使用更少的資源,所以與剪除的沒必要要的分區成比例的變快,而且更可擴展(If you can arrange for queries to prune large numbers of unnecessary partitions from the query execution plan, the queries use fewer resources and are thus proportionally faster and more scalable)。 緩存

例如,若是一個表使用 YEAR, MONTH, DAY 分區,這樣如 WHERE year = 2013, WHERE year < 2010, WHERE year BETWEEN 1995 AND 1998 等 WHERE 子句容許 Impala 除了指定範圍的分區外,跳過全部其餘分區的數據文件。一樣的,WHERE year = 2013 AND month BETWEEN 1 AND 3 甚至能夠剪除更多的分區,只讀取一年中的一部分數據文件。

在執行查詢以前,經過檢查 EXPLAIN 查詢的輸出來檢查查詢分區修剪的效果。例如,下面例子中的表有 3 個分區,而查詢只讀取其中 1 個。EXOLAIN 計劃中的標識符 #partitions=1/3 證實 Impala 能夠進行對應的分區修剪。

[localhost:21000] > insert into census partition (year=2010) values ('Smith'),('Jones');
[localhost:21000] > insert into census partition (year=2011) values ('Smith'),('Jones'),('Doe');
[localhost:21000] > insert into census partition (year=2012) values ('Smith'),('Doe');
[localhost:21000] > select name from census where year=2010;
+-------+
| name  |
+-------+
| Smith |
| Jones |
+-------+
[localhost:21000] > explain select name from census where year=2010;
+------------------------------------------------------------------+
| Explain String                                                   |
+------------------------------------------------------------------+
| PLAN FRAGMENT 0                                                  |
|   PARTITION: UNPARTITIONED                                       |
|                                                                  |
|   1:EXCHANGE                                                     |
|                                                                  |
| PLAN FRAGMENT 1                                                  |
|   PARTITION: RANDOM                                              |
|                                                                  |
|   STREAM DATA SINK                                               |
|     EXCHANGE ID: 1                                               |
|     UNPARTITIONED                                                |
|                                                                  |
|   0:SCAN HDFS                                                    |
|      table=predicate_propagation.census #partitions=1/3 size=12B |
+------------------------------------------------------------------+

經過WHERE 子句中其餘部分的中間屬性,甚至在分區鍵列沒有明確指定常量值的時候,Impala 均可以進行分區修剪(Impala can even do partition pruning in cases where the partition key column is not directly compared to a constant, by applying the transitive property to other parts of the WHERE clause)。這一技術稱爲謂詞傳播(predicate propagation),自 Impala 1.2.2 開始可用。在下面例子裏,表 census 中包含另外一個列存放數據收集的時間(是 10 年採集的)。即便分區鍵列 (YEAR) 沒有對應一個常量, Impala 也能夠推斷只有 YEAR=2010 分區是必需的,並再次只讀取了總分區中 1/3 個分區。

[localhost:21000] > drop table census;
[localhost:21000] > create table census (name string, census_year int) partitioned by (year int);
[localhost:21000] > insert into census partition (year=2010) values ('Smith',2010),('Jones',2010);
[localhost:21000] > insert into census partition (year=2011) values ('Smith',2020),('Jones',2020),('Doe',2020);
[localhost:21000] > insert into census partition (year=2012) values ('Smith',2020),('Doe',2020);
[localhost:21000] > select name from census where year = census_year and census_year=2010;
+-------+
| name  |
+-------+
| Smith |
| Jones |
+-------+
[localhost:21000] > explain select name from census where year = census_year and census_year=2010;
+------------------------------------------------------------------+
| Explain String                                                   |
+------------------------------------------------------------------+
| PLAN FRAGMENT 0                                                  |
|   PARTITION: UNPARTITIONED                                       |
|                                                                  |
|   1:EXCHANGE                                                     |
|                                                                  |
| PLAN FRAGMENT 1                                                  |
|   PARTITION: RANDOM                                              |
|                                                                  |
|   STREAM DATA SINK                                               |
|     EXCHANGE ID: 1                                               |
|     UNPARTITIONED                                                |
|                                                                  |
|   0:SCAN HDFS                                                    |
|      table=predicate_propagation.census #partitions=1/3 size=22B |
|      predicates: census_year = 2010, year = census_year          |
+------------------------------------------------------------------+

在執行查詢以後,馬上檢查 PROFILE 語句的輸出,瞭解實際讀取和處理的數據量更詳細的分析。

假如是在分區表上創建的視圖,全部的分區修剪都是由原使得查詢子句肯定。即便在試圖上的查詢包含了引用分區鍵列的 WHERE 子句,Impala 不會修剪添加的列(If a view applies to a partitioned table, any partition pruning is determined by the clauses in the original query. Impala does not prune additional columns if the query on the view includes extra WHEREclauses referencing the partition key columns)。

分區鍵列

你選擇的分區列應當是那種常常在重要的、大型的查詢中過濾查詢結果的列。一般來講,數據與時間值有關時,使用年、月、日的組合做爲分區列,數據與一些位置有關時使用地理區域做爲分區列。

  • 對於基於時間的數據,拆分出其中的各個部分到單獨的列,由於 Impala 不能基於 TIMESTAMP 列進行分區
  • 分區列的數據類型對存儲需求方面沒有明顯的影響,由於分區列的值不是存放在數據文件裏,而是在 HDFS 目錄名對應的字符串裏
  • Remember that when Impala queries data stored in HDFS, it is most efficient to use multi-megabyte files to take advantage of the HDFS block size. 對於 Parquet 表,塊大小 (數據文件理想大小) 是 1GB。所以,應避免指定太多分區鍵列,這樣會致使個別分區只包含少許數據。例如,假如你天天獲取 1GB 數據,你可能使用年、月、日進行分區;當你每分鐘獲取 5GB 數據時,你可能使用年、月、日、時、分來分區。假如你的數據保護地理組件,假如你每一個郵編都有不少M的數據時,你能夠基於郵編分區;假如不是,那麼你可能須要使用更大的區域,如 city, state, 或 country. state 分區。

爲分區設置不一樣的文件格式

分區表具備爲不一樣的分區設置不一樣的文件格式的靈活性。例如,你原來是接收文本格式數據,而後是 RCFile 格式,最終會接收 Parquet 格式,全部這些數據能夠存放在同一個表裏進行查詢。你只須要確保該表的結構是使用不一樣文件格式的的數據文件分別在單獨的分區。

例如,下面是當你收到不一樣年份的數據時,你可能從文本切換到 Parquet:

[localhost:21000] > create table census (name string) partitioned by (year smallint);
[localhost:21000] > alter table census add partition (year=2012); -- Text format;

[localhost:21000] > alter table census add partition (year=2013); -- Text format switches to Parquet before data loaded;
[localhost:21000] > alter table census partition (year=2013) set fileformat parquet;

[localhost:21000] > insert into census partition (year=2012) values ('Smith'),('Jones'),('Lee'),('Singh');
[localhost:21000] > insert into census partition (year=2013) values ('Flores'),('Bogomolov'),('Cooper'),('Appiah');

如上所述,HDFS 目錄 year=2012 包含文本格式數據文件,而 HDFS 目錄 year=2013 包含 Parquet 數據文件。一如既往,當加載實際數據時,你應當使用 INSERT ... SELECT 或 LOAD DATA 來導入大批量的數據,而不是使用產生少許的對實際查詢低效的文件的 INSERT ... VALUES 語句。

對於其餘的 Impala 沒法本地建立的文件類型,你能夠切換到 Hive 並執行 ALTER TABLE ... SET FILEFORMAT 語句,並在這裏執行 INSERT 或 LOAD DATA 語句。當切換回 Impala 後,執行 REFRESH table_name 語句以便 Impala 感知到經過 Hive 添加的任意分區或新數據。

鏈接查詢性能注意事項

涉及鏈接操做的查詢一般比只引用單個表的查詢更須要調整。鏈接查詢結果集的最大大小是全部鏈接的表中行數的乘積。當鏈接幾個百萬或十億記錄的表時,任何過濾結果集的失誤,或查詢中其餘的低效操做,都將會致使操做沒法完成不得不取消 。

調整 Impala 鏈接查詢的最簡單的技術就是在參與鏈接的每一個表上使用 COMPUTE STATS 語句採集統計信息,而後讓 Impala 基於每個表的大小、每個列不一樣值的個數、等等信息自動的優化查詢。COMPUTE STATS 語句和 鏈接優化(join optimization)是 Impala 1.2.2 引入的新功能。爲了保證每一個表上統計信息的精確,請在表加載數據以後執行 COMPUTE STATS 語句,並在因 INSERT, LOAD DATA, 添加分區等操做致使數據大幅變化以後再次執行。

假如鏈接查詢中全部表的統計信息不可用,或 Impala 選擇的鏈接順序不是最優,你能夠經過在 SELECT 關鍵字以後馬上緊跟 STRAIGHT_JOIN 關鍵字,來覆蓋自動的鏈接順序優化。這時候,Impala 使用表在查詢中出現的順序來指導鏈接如何處理。首先是最大的表,而後是次大的,依此類推。術語"最大""最小"指中間結果集的大小,這些基於做爲結果集一部分的每一個表的行數和列數(The terms "largest" and "smallest" refers to the size of the intermediate result set based on the number of rows and columns from each table that are part of the result set)。例如,若是你鏈接了表 sales 和 customers,查詢多是從產生了 5000 次購買的 100 個用戶中查找結果集。這時候,你應該使用 SELECT ... FROM sales JOIN customers ..., 把 customers 放在右側,由於在這個查詢上下文中它更小。

依賴於表的絕對和相對的大小,Impala 查詢計劃器在執行鏈接查詢的不一樣技術之間進行選擇。廣播鏈接(Broadcast joins) 是默認方式,右側的表被認爲比左側的表小,而且它的內容被髮送到查詢涉及到的其餘節點上。替代的技術稱做分割鏈接(partitioned join) (與分區表無關),更適用於近乎相同大小的大型表的鏈接。使用這一技術,每個表的部份內容被髮送到對應的其餘節點,而後這些行的子集能夠並行處理。廣播和分區鏈接的選擇仍然依賴於鏈接中全部表的可用的、使用 COMPUTE STATS 語句手機的統計信息。

對查詢執行 EXPLAIN 語句,查看該查詢採用了哪一種鏈接策略。若是你發現一個查詢使用了廣播鏈接,而你經過基準測試知道分割鏈接更高效,或者相反狀況時,在查詢上添加提示指定使用的精確的鏈接機制。參見 Hints 瞭解詳細信息。

統計信息不可用時鏈接如何處理

假如鏈接中的一些表的表或列統計信息不可用,Impala 仍然使用可用的那部分信息從新排列表,包含可用統計信息的表放在鏈接的左側,按照總體大小和基數降序排列(Tables with statistics are placed on the left side of the join order, in descending order of cost based on overall size and cardinality)。沒有統計信息的表被認爲大小爲 0,也就是說,它們老是放置在鏈接查詢的右側。

Overriding Join Reordering with STRAIGHT_JOIN

假如由於過期的統計信息或意外的數據分佈, Impala 鏈接查詢很低效,你能夠經過在 SELECT 關鍵字以後緊跟着 STRAIGHT_JOIN 關鍵字來從新排序鏈接的表,使的 Impala 高效。STRAIGHT_JOIN 關鍵字關閉 Impala 內部使用的鏈接子句的從新排序,並根據 查詢中 join 子句中列出的順序優化(The STRAIGHT_JOIN keyword turns off the reordering of join clauses that Impala does internally, and produces a plan that relies on the join clauses being ordered optimally in the query text)。這時,重寫查詢以便最大的表在最左側,跟着是次大的,依此類推直到最小的表放在最右側

在下面的例子裏,基於 BIG 表的子查詢產生一個很是小的結果集,可是這個表仍被視爲好像它是最大的並放置在鏈接順序的第一位。爲最後的鏈接子句使用 STRAIGHT_JOIN 關鍵字,防止最終的表從新排序,保持它做爲最右邊表的鏈接順序(Using STRAIGHT_JOIN for the last join clause prevents the final table from being reordered, keeping it as the rightmost table in the join order)。

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;

Examples of Join Order Optimization


下面的例子演示了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 語句查看將執行的查詢是如何的昂貴(expensive)而不須要實際運行它,而且啓用詳細的 EXPLAIN 計劃包含更詳細的性能導向的信息:最有趣的計劃行---展現了沒有統計信息的鏈接的表--以黑體突出,Impala 沒法正確的估算處理的每一個階段中涉及的行數,一般採用廣播鏈接機制把其中之一的表的完整數據發送到各個節點上(Impala cannot make a good estimate of the number of rows involved at each stage of processing,and is likely to stick with the BROADCAST join mechanism that sends a complete copy of one of the tables to each node)。

[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;
+----------------------------------------------------------+
| Explain String                                           |
+----------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=2.10GB VCores=2  |
|                                                          |
| PLAN FRAGMENT 0                                          |
|   PARTITION: UNPARTITIONED                               |
|                                                          |
|   6:AGGREGATE (merge finalize)                           |
|   |  output: SUM(COUNT(*))                               |
|   |  cardinality: 1                                      |
|   |  per-host memory: unavailable                        |
|   |  tuple ids: 2                                        |
|   |                                                      |
|   5:EXCHANGE                                             |
|      cardinality: 1                                      |
|      per-host memory: unavailable                        |
|      tuple ids: 2                                        |
|                                                          |
| PLAN FRAGMENT 1                                          |
|   PARTITION: RANDOM                                      |
|                                                          |
|   STREAM DATA SINK                                       |
|     EXCHANGE ID: 5                                       |
|     UNPARTITIONED                                        |
|                                                          |
|   3:AGGREGATE                                            |
|   |  output: COUNT(*)                                    |
|   |  cardinality: 1                                      |
|   |  per-host memory: 10.00MB                            |
|   |  tuple ids: 2                                        |
|   |                                                      |
|   2:HASH JOIN                                            | | | join op: INNER JOIN (BROADCAST) | |   |  hash predicates:                                    |
|   |    big.id = medium.id                                | | | cardinality: unavailable | |   |  per-host memory: 2.00GB                             |
|   |  tuple ids: 0 1                                      |
|   |                                                      |
|   |----4:EXCHANGE                                        |
|   |       cardinality: unavailable                       |
|   |       per-host memory: 0B                            |
|   |       tuple ids: 1                                   |
|   |                                                      |
|   0:SCAN HDFS                                            | | table=join_order.big #partitions=1/1 size=23.12GB | | table stats: unavailable | | column stats: unavailable | | cardinality: unavailable | |      per-host memory: 88.00MB                            |
|      tuple ids: 0                                        |
|                                                          |
| PLAN FRAGMENT 2                                          |
|   PARTITION: RANDOM                                      |
|                                                          |
|   STREAM DATA SINK                                       |
|     EXCHANGE ID: 4                                       |
|     UNPARTITIONED                                        |
|                                                          |
|   1:SCAN HDFS                                            | | table=join_order.medium #partitions=1/1 size=4.62GB | | table stats: unavailable | | column stats: unavailable | | cardinality: unavailable | |      per-host memory: 88.00MB                            |
|      tuple ids: 1                                        |
+----------------------------------------------------------+
Returned 64 row(s) in 0.04s

採集全部表的統計信息很簡單,在每個表上執行 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 能夠選擇更有效的鏈接順序而不是按照查詢中從左到右各個表的順序,而且能夠基於表的大小和行數選擇廣播鏈接或分割鏈接策略:

[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 |
|                                                           |
| PLAN FRAGMENT 0                                           |
|   PARTITION: UNPARTITIONED                                |
|                                                           |
|   6:AGGREGATE (merge finalize)                            |
|   |  output: SUM(COUNT(*))                                |
|   |  cardinality: 1                                       |
|   |  per-host memory: unavailable                         |
|   |  tuple ids: 2                                         |
|   |                                                       |
|   5:EXCHANGE                                              |
|      cardinality: 1                                       |
|      per-host memory: unavailable                         |
|      tuple ids: 2                                         |
|                                                           |
| PLAN FRAGMENT 1                                           |
|   PARTITION: RANDOM                                       |
|                                                           |
|   STREAM DATA SINK                                        |
|     EXCHANGE ID: 5                                        |
|     UNPARTITIONED                                         |
|                                                           |
|   3:AGGREGATE                                             |
|   |  output: COUNT(*)                                     |
|   |  cardinality: 1                                       |
|   |  per-host memory: 10.00MB                             |
|   |  tuple ids: 2                                         |
|   |                                                       |
|   2:HASH JOIN                                             |
|   |  join op: INNER JOIN (BROADCAST)                      |
|   |  hash predicates:                                     |
|   |    big.id = medium.id                                 |
|   |  cardinality: 1443004441                              |
|   |  per-host memory: 839.23MB                            |
|   |  tuple ids: 1 0                                       |
|   |                                                       |
|   |----4:EXCHANGE                                         |
|   |       cardinality: 200000000                          |
|   |       per-host memory: 0B                             |
|   |       tuple ids: 0                                    |
|   |                                                       |
|   1:SCAN HDFS                                             |
|      table=join_order.big #partitions=1/1 size=23.12GB    |
|      table stats: 1000000000 rows total                   |
|      column stats: all                                    |
|      cardinality: 1000000000                              |
|      per-host memory: 88.00MB                             |
|      tuple ids: 1                                         |
|                                                           |
| PLAN FRAGMENT 2                                           |
|   PARTITION: RANDOM                                       |
|                                                           |
|   STREAM DATA SINK                                        |
|     EXCHANGE ID: 4                                        |
|     UNPARTITIONED                                         |
|                                                           |
|   0:SCAN HDFS                                             |
|      table=join_order.medium #partitions=1/1 size=4.62GB  |
|      table stats: 200000000 rows total                    |
|      column stats: all                                    |
|      cardinality: 200000000                               |
|      per-host memory: 88.00MB                             |
|      tuple ids: 0                                         |
+-----------------------------------------------------------+
Returned 64 row(s) in 0.04s

[localhost:21000] > explain select count(*) from small join big where big.id = small.id;
Query: explain select count(*) from small join big where big.id = small.id
+-----------------------------------------------------------+
| Explain String                                            |
+-----------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=101.15MB VCores=2 |
|                                                           |
| PLAN FRAGMENT 0                                           |
|   PARTITION: UNPARTITIONED                                |
|                                                           |
|   6:AGGREGATE (merge finalize)                            |
|   |  output: SUM(COUNT(*))                                |
|   |  cardinality: 1                                       |
|   |  per-host memory: unavailable                         |
|   |  tuple ids: 2                                         |
|   |                                                       |
|   5:EXCHANGE                                              |
|      cardinality: 1                                       |
|      per-host memory: unavailable                         |
|      tuple ids: 2                                         |
|                                                           |
| PLAN FRAGMENT 1                                           |
|   PARTITION: RANDOM                                       |
|                                                           |
|   STREAM DATA SINK                                        |
|     EXCHANGE ID: 5                                        |
|     UNPARTITIONED                                         |
|                                                           |
|   3:AGGREGATE                                             |
|   |  output: COUNT(*)                                     |
|   |  cardinality: 1                                       |
|   |  per-host memory: 10.00MB                             |
|   |  tuple ids: 2                                         |
|   |                                                       |
|   2:HASH JOIN                                             |
|   |  join op: INNER JOIN (BROADCAST)                      |
|   |  hash predicates:                                     |
|   |    big.id = small.id                                  |
|   |  cardinality: 1000000000                              |
|   |  per-host memory: 3.15MB                              |
|   |  tuple ids: 1 0                                       |
|   |                                                       |
|   |----4:EXCHANGE                                         |
|   |       cardinality: 1000000                            |
|   |       per-host memory: 0B                             |
|   |       tuple ids: 0                                    |
|   |                                                       |
|   1:SCAN HDFS                                             |
|      table=join_order.big #partitions=1/1 size=23.12GB    |
|      table stats: 1000000000 rows total                   |
|      column stats: all                                    |
|      cardinality: 1000000000                              |
|      per-host memory: 88.00MB                             |
|      tuple ids: 1                                         |
|                                                           |
| PLAN FRAGMENT 2                                           |
|   PARTITION: RANDOM                                       |
|                                                           |
|   STREAM DATA SINK                                        |
|     EXCHANGE ID: 4                                        |
|     UNPARTITIONED                                         |
|                                                           |
|   0:SCAN HDFS                                             |
|      table=join_order.small #partitions=1/1 size=17.93MB  |
|      table stats: 1000000 rows total                      |
|      column stats: all                                    |
|      cardinality: 1000000                                 |
|      per-host memory: 32.00MB                             |
|      tuple ids: 0                                         |
+-----------------------------------------------------------+
Returned 64 row(s) in 0.03s

當相似這些的查詢實際運行時,執行時間是相對固定的,無論查詢語句中表的順序如何。下面的例子使用了惟一的 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
  Note: 當檢測鏈接查詢的性能和鏈接順序優化的有效性時,請確保查詢涉及到足夠的數據和集羣資源,以便能在查詢計劃中看出不一樣。例如,只有幾兆大小的單個數據文件將會存放在一個 HDFS 塊裏,並只被單個節點處理。一樣的,假如你使用單節點或兩個節點的集羣,廣播鏈接和分割鏈接策略的效率可能沒什麼分別。



Impala 如何使用統計信息進行查詢優化

當統計信息可用時,Impala 能夠更好的優化複雜的或多表查詢,能夠更好地理解數據量和值的分佈,並使用這些信息幫助查詢並行處理和分佈負載。下面的章節描述了 Impala 可使用的統計信息的分類,以及如何產生這些信息並保持最新。

原來 Impala 依靠 Hive 採集統計信息的機制,經過 Hive ANALYZE TABLE 語句初始化一個 MapReduce 做業進行。爲了更好的性能、用戶友好性和可靠性, 在 1.2.1 以後,Impala 實現了本身的 COMPUTE STATS 語句,以及相關的 SHOW TABLE STATS 和 SHOW COLUMN STATS 語句。

表統計信息

當 metastore 數據庫中的元數據可用時,Impala 查詢計劃器可使用整個表和分區的統計信息。這些元數據用於本表的某些優化,並和列統計信息組合用於其餘優化。

當向表或分區加載數據加載數據後,使用如下技術之一採集表的統計信息:

  • 在 Impala 中執行 COMPUTE STATS 語句。這一在 Impala 1.2.2 新引入的語句是首選方法,由於:
    • 它在單個操做中採集表、表的全部分區和全部列的統計信息
    • 它不依賴於任意特殊的 Hive 設置、 metastore 配置、或單獨的數據庫來存放統計信息
    • 它使用 Impala 查詢基礎架構來計算行數、不一樣值個數等等,一般比用 Hive ANALYZE TABLE statement.
  • 當 Hive 中設置 hive.stats.autogather 爲啓用時,經過 Hive INSERT OVERWRITE 語句加載數據
  • 爲整個表或特定分區在 Hive 中執行 ANALYZE TABLE 語句:
    ANALYZE TABLEtablename[PARTITION(partcol1[=val1],partcol2[=val2], ...)] COMPUTE STATISTICS [NOSCAN];
    例如,爲非分區表採集統計信息:
    ANALYZE TABLE customer COMPUTE STATISTICS;
    爲以 state 和 city 分區列的分區表 store 表採集全部分區的統計信息:
    ANALYZE TABLE store PARTITION(s_state, s_county) COMPUTE STATISTICS;
    只採集分區表 store 中 California 分區的統計信息:
    ANALYZE TABLE store PARTITION(s_state='CA', s_county) COMPUTE STATISTICS;

使用 SHOW TABLE STATS table_name 語句,查看錶的統計信息是否可用,以及統計信息的詳細內容。參考 SHOW Statement 瞭解詳細信息。

假如你使用基於 Hive 的方法採集統計信息,參見 the Hive wiki 瞭解關於 Hive 的配置要求。 Cloudera 推薦使用 Impala COMPUTE STATS 語句以免 Hive 採集統計信息程序潛在的配置和可擴展性方面的問題。

列統計信息

當 metastore 數據庫中的元數據可用時,Impala 查詢計劃器可使用單個列的統計信息。這一技術對於比較鏈接查詢中全部表的鏈接列,以幫助評估查詢中每個表將返回多少行最有價值。目前 Impala 自身不會自動建立這些元數據。使用 Hive 中的 ANALYZE TABLE 語句收集這些統計信息(不管表是在 Impala 仍是 Hive 中建立的,這一語句均可以正常工做)。

  Note:Impala 中列統計信息很重要,可是對於應用表,你也一樣須要表的統計信息,像在 表統計信息 中描述的那樣。假如你使用 Impala COMPUTE STATS 語句,表和表中全部列的統計信息都會自動同時收集。

對於特定的一組列,使用 SHOW COLUMN STATS table_name 語句檢查列統計信息是否可用,或檢查針對引用這系列的表的查詢的擴展的 EXPLAIN 輸出。參見 SHOW 語句EXPLAIN 語句瞭解詳細信息。

經過 ALTER TABLE 手工設置統計信息


全部統計信息中最關鍵的部分是表(未分區的表)或分區(分區表)中的行數。COMPUTE STATS 語句老是採集全部列的統計信息以及整個表的統計信息。假如在添加了一個分區或插入數據以後,進行完整的 COMPUTE STATS 操做實際不可行時,或者當行數不一樣時,能夠預見 Impala 將產生更好的執行計劃時,你能夠經過 ALTER TABLE 語句手工設置行數:

create table analysis_data stored as parquet as select * from raw_data;
Inserted 1000000000 rows in 181.98s
compute stats analysis_data;
insert into analysis_data select * from smaller_table_we_forgot_before;
Inserted 1000000 rows in 15.32s
-- 如今表裏共有 1001000000 行。咱們能夠更新統計信息中的這一個數據點
alter table analysis_data set tblproperties('numRows'='1001000000');

對於分區表,同時更新每個分區的行數和整個表的行數:

-- 若是原來表中包含 1000000 行,咱們新添加了一個分區
-- 修改該分區和整個表的 numRows 屬性
alter table partitioned_data partition(year=2009, month=4) set tblproperties ('numRows'='30000');
alter table partitioned_data set tblproperties ('numRows'='1030000');

實際上,COMPUTE STATS 語句已經夠快了,這一技術是沒必要要的。這一方法最大的價值就是能夠調整 numRows 值的大小來產生理想的鏈接順序從而解決性能問題(It is most useful as a workaround for in case of performance issues where you might adjust the numRowsvalue higher or lower to produce the ideal join order)。



在 Impala 使用表和列統計信息的例子


下面的例子經過一系列的 SHOW TABLE STATS, SHOW COLUMN STATS, ALTER TABLE, SELECT , INSERT 語句來演示了 Impala 如何使用統計信息幫助優化查詢的各個方面。

這一例子展現了 STORE 表的表和列的統計信息,這個表使用的是 TPC-DS 決策支持系統基準測試中的表。這是一個只有 12 行數據的小表。最初,在使用 COMPUTE STATS 採集統計信息以前,大多數數字列顯示佔位符 -1,表示這一數字是未知的。這一待填充的數值是容易在物理層計量或推斷出的,如文件個數,文件的總數據大小,以及對具備固定大小如 INT,FLOAT,TIMESTAMP 等數據類型的最大和平均大小(The figures that are filled in are values that are easily countable or deducible at the physical level, such as the number of files, total data size of the files, and the maximum and average sizes for data types that have a constant size such as INT, FLOAT, and TIMESTAMP)。

[localhost:21000] > show table stats store;
+-------+--------+--------+--------+
| #Rows | #Files | Size   | Format |
+-------+--------+--------+--------+
| -1    | 1      | 3.08KB | TEXT   |
+-------+--------+--------+--------+
Returned 1 row(s) in 0.03s
[localhost:21000] > show column stats store;
+--------------------+-----------+------------------+--------+----------+----------+
| Column             | Type      | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------------------+-----------+------------------+--------+----------+----------+
| s_store_sk         | INT       | -1               | -1     | 4        | 4        |
| s_store_id         | STRING    | -1               | -1     | -1       | -1       |
| s_rec_start_date   | TIMESTAMP | -1               | -1     | 16       | 16       |
| s_rec_end_date     | TIMESTAMP | -1               | -1     | 16       | 16       |
| s_closed_date_sk   | INT       | -1               | -1     | 4        | 4        |
| s_store_name       | STRING    | -1               | -1     | -1       | -1       |
| s_number_employees | INT       | -1               | -1     | 4        | 4        |
| s_floor_space      | INT       | -1               | -1     | 4        | 4        |
| s_hours            | STRING    | -1               | -1     | -1       | -1       |
| s_manager          | STRING    | -1               | -1     | -1       | -1       |
| s_market_id        | INT       | -1               | -1     | 4        | 4        |
| s_geography_class  | STRING    | -1               | -1     | -1       | -1       |
| s_market_desc      | STRING    | -1               | -1     | -1       | -1       |
| s_market_manager   | STRING    | -1               | -1     | -1       | -1       |
| s_division_id      | INT       | -1               | -1     | 4        | 4        |
| s_division_name    | STRING    | -1               | -1     | -1       | -1       |
| s_company_id       | INT       | -1               | -1     | 4        | 4        |
| s_company_name     | STRING    | -1               | -1     | -1       | -1       |
| s_street_number    | STRING    | -1               | -1     | -1       | -1       |
| s_street_name      | STRING    | -1               | -1     | -1       | -1       |
| s_street_type      | STRING    | -1               | -1     | -1       | -1       |
| s_suite_number     | STRING    | -1               | -1     | -1       | -1       |
| s_city             | STRING    | -1               | -1     | -1       | -1       |
| s_county           | STRING    | -1               | -1     | -1       | -1       |
| s_state            | STRING    | -1               | -1     | -1       | -1       |
| s_zip              | STRING    | -1               | -1     | -1       | -1       |
| s_country          | STRING    | -1               | -1     | -1       | -1       |
| s_gmt_offset       | FLOAT     | -1               | -1     | 4        | 4        |
| s_tax_precentage   | FLOAT     | -1               | -1     | 4        | 4        |
+--------------------+-----------+------------------+--------+----------+----------+
Returned 29 row(s) in 0.04s

使用 Hive ANALYZE TABLE 語句採集列的統計信息,你必須指定要採集統計信息的每個列。而 Impala COMPUTE STATS 語句自動採集全部列的統計信息,由於它較快的讀取整個表並高效的計算全部列的值。下面例子展現了執行 COMPUTE STATS 語句以後,表和全部列的統計信息都被填充:

[localhost:21000] > compute stats store;
+------------------------------------------+
| summary                                  |
+------------------------------------------+
| Updated 1 partition(s) and 29 column(s). |
+------------------------------------------+
Returned 1 row(s) in 1.88s
[localhost:21000] > show table stats store;
+-------+--------+--------+--------+
| #Rows | #Files | Size   | Format |
+-------+--------+--------+--------+
| 12    | 1      | 3.08KB | TEXT   |
+-------+--------+--------+--------+
Returned 1 row(s) in 0.02s
[localhost:21000] > show column stats store;
+--------------------+-----------+------------------+--------+----------+-------------------+
| Column             | Type      | #Distinct Values | #Nulls | Max Size | Avg Size          |
+--------------------+-----------+------------------+--------+----------+-------------------+
| s_store_sk         | INT       | 12               | 0      | 4        | 4                 |
| s_store_id         | STRING    | 6                | 0      | 16       | 16                |
| s_rec_start_date   | TIMESTAMP | 4                | 0      | 16       | 16                |
| s_rec_end_date     | TIMESTAMP | 3                | 6      | 16       | 16                |
| s_closed_date_sk   | INT       | 3                | 9      | 4        | 4                 |
| s_store_name       | STRING    | 8                | 0      | 5        | 4.25              |
| s_number_employees | INT       | 9                | 0      | 4        | 4                 |
| s_floor_space      | INT       | 10               | 0      | 4        | 4                 |
| s_hours            | STRING    | 2                | 0      | 8        | 7.083300113677979 |
| s_manager          | STRING    | 7                | 0      | 15       | 12                |
| s_market_id        | INT       | 7                | 0      | 4        | 4                 |
| s_geography_class  | STRING    | 1                | 0      | 7        | 7                 |
| s_market_desc      | STRING    | 10               | 0      | 94       | 55.5              |
| s_market_manager   | STRING    | 7                | 0      | 16       | 14                |
| s_division_id      | INT       | 1                | 0      | 4        | 4                 |
| s_division_name    | STRING    | 1                | 0      | 7        | 7                 |
| s_company_id       | INT       | 1                | 0      | 4        | 4                 |
| s_company_name     | STRING    | 1                | 0      | 7        | 7                 |
| s_street_number    | STRING    | 9                | 0      | 3        | 2.833300113677979 |
| s_street_name      | STRING    | 12               | 0      | 11       | 6.583300113677979 |
| s_street_type      | STRING    | 8                | 0      | 9        | 4.833300113677979 |
| s_suite_number     | STRING    | 11               | 0      | 9        | 8.25              |
| s_city             | STRING    | 2                | 0      | 8        | 6.5               |
| s_county           | STRING    | 1                | 0      | 17       | 17                |
| s_state            | STRING    | 1                | 0      | 2        | 2                 |
| s_zip              | STRING    | 2                | 0      | 5        | 5                 |
| s_country          | STRING    | 1                | 0      | 13       | 13                |
| s_gmt_offset       | FLOAT     | 1                | 0      | 4        | 4                 |
| s_tax_precentage   | FLOAT     | 5                | 0      | 4        | 4                 |
+--------------------+-----------+------------------+--------+----------+-------------------+
Returned 29 row(s) in 0.04s

下面的例子展現了分區表中統計信息如何表示。這時,咱們設置了一個存放世界上最瑣碎的戶籍數據的表,包含一個 STRING 字段,根據 YEAR 列進行分區。表統計信息中每個分區都包含一個單獨的實體,再加上最終的總數。對於分區列,列統計信息中包含一些容易推斷的事實,如不一樣值的個數(分區子目錄的個數) 和 NULL 值的個數(分區列中不可能出現)。

localhost:21000] > describe census;
+------+----------+---------+
| name | type     | comment |
+------+----------+---------+
| name | string   |         |
| year | smallint |         |
+------+----------+---------+
Returned 2 row(s) in 0.02s
[localhost:21000] > show table stats census;
+-------+-------+--------+------+---------+
| year  | #Rows | #Files | Size | Format  |
+-------+-------+--------+------+---------+
| 2000  | -1    | 0      | 0B   | TEXT    |
| 2004  | -1    | 0      | 0B   | TEXT    |
| 2008  | -1    | 0      | 0B   | TEXT    |
| 2010  | -1    | 0      | 0B   | TEXT    |
| 2011  | 0     | 1      | 22B  | TEXT    |
| 2012  | -1    | 1      | 22B  | TEXT    |
| 2013  | -1    | 1      | 231B | PARQUET |
| Total | 0     | 3      | 275B |         |
+-------+-------+--------+------+---------+
Returned 8 row(s) in 0.02s
[localhost:21000] > show column stats census;
+--------+----------+------------------+--------+----------+----------+
| Column | Type     | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------+----------+------------------+--------+----------+----------+
| name   | STRING   | -1               | -1     | -1       | -1       |
| year   | SMALLINT | 7                | 0      | 2        | 2        |
+--------+----------+------------------+--------+----------+----------+
Returned 2 row(s) in 0.02s

下面的例子演示了在 Impala 中執行 COMPUTE STATS 語句後統計信息是如何填充的。

[localhost:21000] > compute stats census;
+-----------------------------------------+
| summary                                 |
+-----------------------------------------+
| Updated 3 partition(s) and 1 column(s). |
+-----------------------------------------+
Returned 1 row(s) in 2.16s
[localhost:21000] > show table stats census;
+-------+-------+--------+------+---------+
| year  | #Rows | #Files | Size | Format  |
+-------+-------+--------+------+---------+
| 2000  | -1    | 0      | 0B   | TEXT    |
| 2004  | -1    | 0      | 0B   | TEXT    |
| 2008  | -1    | 0      | 0B   | TEXT    |
| 2010  | -1    | 0      | 0B   | TEXT    |
| 2011  | 4     | 1      | 22B  | TEXT    |
| 2012  | 4     | 1      | 22B  | TEXT    |
| 2013  | 1     | 1      | 231B | PARQUET |
| Total | 9     | 3      | 275B |         |
+-------+-------+--------+------+---------+
Returned 8 row(s) in 0.02s
[localhost:21000] > show column stats census;
+--------+----------+------------------+--------+----------+----------+
| Column | Type     | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------+----------+------------------+--------+----------+----------+
| name   | STRING   | 4                | 1      | 5        | 4.5      |
| year   | SMALLINT | 7                | 0      | 2        | 2        |
+--------+----------+------------------+--------+----------+----------+
Returned 2 row(s) in 0.02s

關於在統計信息可用時,演示一些查詢工做方式不一樣的例子,參見 Examples of Join Order Optimization。在採集統計信息以前和以後,觀察 EXPLAIN 的輸出,你能夠看到 Impala 使用不一樣方式執行同一個查詢。對比以前和以後的查詢時間,檢查以前和以後 PROFILE 輸出的吞吐量的值, to verify how much the improved plan speeds up performance.


Impala 查詢基準測試


與其餘 Hadoop 組件相似,由於 Impala 是設計用來處理分佈式環境中大量數據的,因此應使用真實的數據和集羣配置進行性能測試。使用多節點的集羣而不是單節點的;對包含 TB 數據的表進行查詢而不是幾十G的。Impala 全部使用的並行處理技術最適合用於超出了單個服務器容量的負載。

當你執行查詢返回大量的行,打印輸出結果所花費的 CPU 時間是巨大的,爲實際查詢時間添加了不許確的度量(the CPU time to pretty-print the output can be substantial, giving an inaccurate measurement of the actual query time)。請考慮在 impala-設立了 命令中使用 -B 選項關閉打印結果,而可選的 -o 選項能夠保存查詢結果到一個文件而不是打印到屏幕上。參見 impala-shell Command-Line Options 瞭解詳細信息。



控制資源使用

經過爲 impalad 守護進程指定 -mem_limits 選項,你能夠限制查詢執行時 Impala 使用的內存量。參見 Modifying Impala Startup Options 瞭解詳細信息。這一限制僅對查詢直接消耗的內存有效;Impala 在啓動時保留了額外的內存,例如用於緩存元數據。

對於生產部署,Cloudera 推薦使用如 cgroups 機制實現資源隔離,能夠在 Cloudera Manager 中配置。參見 Managing Clusters with Cloudera Manager 瞭解詳細信息。

當你結合 CDH 5 使用 Impala 時,你能夠像在 Using Resource Management with Impala (CDH 5 Only) 中描述的那樣使用 YARN 資源管理框架。目前 CDH 5 還是 beta 版;用於 CDH 5 beta 版的對應 Impala 版本是 1.2.0。

理解 EXPLAIN 計劃

EXPLAIN 語句提供查詢將要執行的邏輯步驟的大綱,例如工做在節點之間如何分佈,以及中間結果如何組合產生最終結果集。你能夠在實際執行查詢以前看到這些詳細信息。你可使用這些信息來檢查查詢是否使用一些很是意外的或低效的方式執行。

在查詢 profile 報告的開始部分,EXPLAIN 計劃一樣被打印出來,以便於檢查查詢的邏輯和物理的各個方面。

EXPLAIN 輸出的細節的數量由 EXPLAIN_LEVEL 查詢選項控制。當性能調整時複覈表和列的統計信息時,或與 CDH5 中資源管理功能聯合評估查詢資源使用狀況時(or when estimating query resource usage in conjunction with the resource management features in CDH 5),一般從 normal 修改成 verbose (或 0 到 1)。

理解查詢 Profile

PROFILE 語句在 impala-shell 中可用,產生一個最近執行語句的詳細的底層報告。 不像在 Understanding the EXPLAIN Plan 中描述的 EXPLAIN 那樣,這一信息僅當查詢執行完成後可用。它展現了物理細節如每一節點讀取的字節數,最大內存使用等等信息。你可使用這些信息肯定查詢是 I/O 密集(I/O-bound)仍是 CPU 密集(CPU-bound),是否一些網絡條件達到瓶頸,是否一臺放緩影響到了部分節點而不影響另外一部分(whether a slowdown is affecting some nodes but not others),並檢查推薦配置如 short-circuit local reads 是否生效。

EXPLAIN plan 一樣被打印在查詢 profile 報告的開始,以便於檢查查詢的邏輯和物理的各個方面。在 EXPLAIN_LEVEL 中描述的 EXPLAIN_LEVEL 查詢選項,一樣對控制 PROFILE 命令中產生的 EXPLAIN 輸出打印的詳細程度有效


測試 Impala 性能


測試以確保 Impala 爲性能進行了最優配置。假如你沒有使用 Cloudera Manager 安裝的 Impala,完成本主題中描述的內容以幫助確認已經合適的配置。即便你使用 Cloudera Manager 安裝的 Impala,已經自動應用合適的配置,這一過程能夠檢驗 Impala 設置是否正確。


檢查 Impala 配置值

你可使用瀏覽器鏈接到 Impala 服務器檢查 Impala 的配置值:

檢查 Impala 配置值:

  1. 使用瀏覽器鏈接到你的環境中運行 impalad 進程的主機之一。使用相似格式鏈接 http://hostname:port/varz
      Note: 在前面的例子中,替換 hostname 和 port 爲你的 Impala 的名稱和端口。默認端口是 25000
  2. 查看已配置的值

    例如,檢查你的系統是否啓用了本地塊跟蹤信息(block locality tracking information),應檢查 dfs.datanode.hdfs-blocks-metadata.enabled 的值是否爲 true

檢查數據本地化(data locality):

  1. 在多個節點上均可用的數據集上執行查詢。例如,對具備合理機會傳播到多個數據節點上表 MyTable 進行查詢:
    [impalad-host:21000] > SELECT COUNT (*) FROM MyTable
  2. 當查詢完成後,檢查 Impala 日誌的內存。你可能會發現相似下面的消息:
    Total remote scan volume = 0

遠程掃描的存在標識 impalad 沒有運行在正確的節點上。當一些數據節點上沒有運行 impalad 或沒法運行,由於啓動查詢的 impalad 實例沒法鏈接到一個或多個 impalad 實例(This can be because some DataNodes do not have impalad running or it can be because the impalad instance that is starting the query is unable to contact one or more of the impalad instances)。

理解這些問題的緣由:

  1. 鏈接到調試web服務器。默認的,服務器運行在 25000 端口。這一頁面列出了你集羣中全部在運行的 impalad 實例。假如列出的實例少於你的預期,這一般代表一些 DataNode 沒有運行 impalad。請確保全部 DataNode 都啓動了 impalad
  2. 假如你使用多宿主(multi-homed)主機,請確保 Impala 守護進程的主機名解析到運行的 impalad(If you are using multi-homed hosts, ensure that the Impala daemon's hostname resolves to the interface on which impalad is running)。Impala 在啓動 impalad 時顯示主機名。假如須要明確設置主機名,請使用 --hostname 標誌
  3. 檢查 statestored 是否正常運行。複查 state store 日誌的內容以確保全部的 impalad 實例別列爲鏈接到 state store


複查 Impala 日誌

你能夠複查 Impala 日誌的內容,查找短路讀取(short-circuit reads)或塊本地跟蹤(block location tracking)沒有正常運行的標誌。在檢查日誌以前,對一個小的 HDFS 數據集執行一個簡單的查詢。完成一個查詢任務使用當前設置產生日誌信息。啓動 Impala 和執行查詢的信息能夠在 Starting Impala 和 Using the Impala Shell 找到。登陸信息能夠在 Using Impala Logging 中找到。日誌信息和對應的描述以下:

Log Message

Interpretation

Unknown disk id. This will negatively affect performance. Check your hdfs settings to enable block location metadata

Tracking block locality 未啓用

Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

Native checksumming 未啓用

相關文章
相關標籤/搜索