Impala基礎知識

概述

基於Hive的大數據實時分析查詢引擎,

Hive適合於長時間的批處理查詢分析,而Impala適合於實時交互式SQL查詢。

建表語句

建表語句中的location指向實際數據的路徑;
瞭解一個表的基本類別可以通過show create table命令;
刪除impala的一行數據:不是delete

基本概念

元數據與數據

元數據是記錄數據的數據。Impala的數據就是文件,而元數據是記錄文件存在什麼位置,多少個,大小,時間等。

刷新

invalidate metadata和refresh
refresh輕量級,適用於數據更新(不是Impala途徑增加或者刪除數據)的場景;
invalidate metadata,適用於表結構發生改變(非Impala途徑創建或者修改表結構);

統計信息

收集統計信息:compute stats db.table
查看錶統計信息:show table stats db.table
查看字段統計信息:show column stats db.table

用途:
join query缺少統計信息時,可能會生成錯誤的執行計劃,查詢緩慢;

join

join算法有兩類:

  1. hash join:對於等值join,Impala將採用hash的方式處理,具體又分兩種策略:broadcast 和 Shuffle。
    1. broadcast join 非常適合右表是小表的情形,Impala先將右表複製到各個節點,再和左表做join
    2. shuffle join:亦partitioned join,適合大表和大表關聯。partitioned join 和右表的 partition 沒有直接關係,Impala會將右表打散成N份,發送到左表所在的節點,然後join;有點類似於mapreduce中的shuffle
  2. nested loop join:針對非等值join,Impala將使用 nested loop join,這時不能設置 SHUFFLE/BROADCAST hint,也不能使用 spill disk 功能。Impala的非等值join的效率較低,Vertica的效率非常高,Hive直接不支持

broadcast vs shuffle

broadcast,廣播連接,Impala默認方式,大表一定要放在左邊,因爲impala在廣播右側表,所有右側表會複製到需要右側表進行聯接的所有節點。右側的表被認爲比左側的表小,並且它的內容被髮送到查詢涉及到的其他節點上。

在join後面加[shuffle],將broadcast join轉換爲shuffle join,

替代的技術稱作分割連接(partitioned join,與分區表無關),更適用於近乎相同大小的大型表的連接,每一個表的部分內容被髮送到對應的其他節點,然後這些行的子集可以並行處理。廣播和分區連接的選擇仍然依賴於連接中所有表的可用的、使用 COMPUTE STATS 語句的統計信息。

Impala join查詢最簡單的優化手段就是通過使用compute stats來收集join中每張表的統計信息,然後由Impala根據表的大小、列的唯一值數目等來自動優化查詢。爲了更加精確地獲取每張表的統計信息,每次表的數據變更時(如執行insert、load data、add partition、或drop partition等)都要重新執行一遍compute stats。

如果join查詢中表的統計信息不全或者Impala選擇的join順序不是最優時,你可以在select [distinct 、all]之後指定straight_join來覆蓋掉impala的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;


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;
這樣Impala就會使用查詢語句中表的順序來指導join的處理。



當使用STRAIGHT_JOIn技術時,你必須手動指定join查詢中表的順序而不是依賴於Impala優化器。Impala優化器使用特殊的手段來估算join中每個階段的結果集大小,而對於手動指定順序來說,可以根據如下方式開始,然後再手動調節來達到最優:

首先指定最大的表,此表一般保存於磁盤中
指定最小的表,第二張表、第三張表等等之後的表都是通過網絡傳輸的,你需要對這些結果集進行裁剪處理以降低傳輸數據量
指定次小表,再到次次小表等
例如:如果你的表的大小如下:BIG、MEDIUM、SMALL和TINY,那麼你的順序應該如此:BIG join TINY join SMALL join MEDIUM。


Impala查詢優化器根據表的絕對或者相對大小來選擇不同技術來執行join查詢。默認情況下是 broadcast join,右邊的表都是小於左邊的表,右邊的表的內容會被分發到其他的查詢節點中。

另一種技術就是partitioned join,這種技術更加適用於大小差不多大的大表join,使用這種方式的話,每張表中的分區都會把數據分發到其他節點中,這樣就可以這些數據子集就可以併發處理了。 broadcast或者partition join的選擇是根據compute stats採集到的可用統計指標來衡量的。對於指定查詢語句,可以通過執行EXPLAIN就可以查看選用的是哪個join策略。

統計指標不可用時join如何查詢
   當join中表或者列的統計指標不可用時,Impala將無統計指標的表認爲統計指標都爲0,這些表都將作爲右表處理。

外部表

創建表的時候可以通過指定location來指定表文件的存放路徑,如果不指定的話,默認是將數據存放在/user/hive/warehouse/庫名下。
未被external修飾的表是內部表(managed table),被external修飾的是外部表(external table)

區別:

  1. 內部表的數據是由Hive自身管理的,外部表的數據是由HDFS管理的;
  2. 刪除內部表會刪除存儲在hive元數據庫的元數據和存儲在HDFS的文件數據;刪除外部表只刪除元數據不刪除存儲的數據;
  3. 兩者都可以在建表的時候指定location,指定數據文件的存放位置;如果不指定的話,默認都是在/user/hive/warehouse/目錄下(這個目錄是可以在配置文件中修改的)。
  4. 兩者的load 操作都會移動數據

分區表

存儲格式

通常對於大數據量來說,Parquet文件格式是最佳的

操作符

Impala特有操作符

ILIKE:忽略大小寫的 like 操作符
REGEXP:正則匹配操作符
RLIKE:同 REGEXP 操作符
IREGEXP:忽略大小寫的正則匹配符
IS DISTINCT FROM:判斷前後兩個表達式是否不相等,和<>操作符類似,但 null IS DISTINCT FROM null 返回 false
IS not DISTINCT FROM:判斷前後兩個表達式是否相等,和=操作符類似,唯一不同的是,處理 null 時候,null IS not DISTINCT FROM null 結果爲 ture




異常

set DISABLE_UNSAFE_SPILLS=0/FALSE; #0(FALSE)內存運算瀕臨溢出時轉爲磁盤運算,1(TRUE)時,當內存溢出時直接報內存溢出“Memory limit exceeded”錯誤

set mem_limit=-1 #取消內存限制;

java.sql.SQLException:memory limit exceeded常見原因:

優化技巧

在優化之前,可先拿到查詢計劃,類似mysql explain查詢計劃。在執行後也可以查看詳細的執行信息。

查詢計劃

Impala提供三種方式得知查詢計劃

  1. EXPLAIN:獲取執行計劃,而無須真正的執行query
  2. PROFILE:產生一個關於最近一次查詢的底層報告的詳細信息展示。與EXPLAIN不同,這些信息只在查詢完成之後纔會生成,它顯示每個節點上的物理詳細信息如:讀取的字節數,最大內存消耗等。
    想要查看一個查詢的物理性能特性的概覽,可以在執行查詢之後立馬在impala-shell中執行PROFILE命令,輸出的信息中將展示哪個階段耗時最多,以及每一階段估算的內存消耗、行數與實際的差異。進行性能分析,可根據這些信息來確定查詢時I/O密集型,還是CPU密集型,網絡是否導致瓶頸,是否某些節點性能差但是其它節點性能好等信息。
  3. SUMMAY:輸出每一階段的耗時,可以快速地瞭解查詢的性能瓶頸,SUMMARY輸出也會在PROFILE的頭部輸出的顯示。
    想要了解查詢的詳細性能特徵,可以在執行查詢之後立馬在impala-shell中執行PROFILE命令,這些底層的信息包括內存、CPU、I/O以及網絡消耗的詳細信息,只能在一個真實的查詢之後纔可用。

EXPLAIN語句概述了查詢將執行的邏輯步驟,例如如何在節點間分配工作以及中間結果如何合併爲最終結果, 這些你都可以在查詢真正執行之前獲得,你可以使用這些信息來檢查查詢是否會以某種非高效的方式執行。

explain select ds,count(*) from t_ed_xxxx_newuser_read_feature_n group by ds order by ds;
+----------------------------------------------------------------------------------------------+
| Explain String                                                                               |
+----------------------------------------------------------------------------------------------+
| Max Per-Host Resource Reservation: Memory=9.94MB                                             |
| Per-Host Resource Estimates: Memory=27.00MB                                                  |
|                                                                                              |
| PLAN-ROOT SINK                                                                               |
| |                                                                                            |
| 05:MERGING-EXCHANGE [UNPARTITIONED]                                                          |
| |  order by: ds ASC                                                                          |
| |                                                                                            |
| 02:SORT                                                                                      |
| |  order by: ds ASC                                                                          |
| |                                                                                            |
| 04:AGGREGATE [FINALIZE]                                                                      |
| |  output: count:merge(*)                                                                    |
| |  group by: ds                                                                              |
| |                                                                                            |
| 03:EXCHANGE [HASH(ds)]                                                                       |
| |                                                                                            |
| 01:AGGREGATE [STREAMING]                                                                     |
| |  output: sum_init_zero(default.t_ed_xxxx_newuser_read_feature_n.parquet-stats: num_rows) |
| |  group by: ds                                                                              |
| |                                                                                            |
| 00:SCAN HDFS [default.t_ed_xxxx_newuser_read_feature_n]                                    |
|    partitions=372/372 files=2562 size=15.15GB

自底向上讀取EXPLAIN的輸出:
00階段: 顯示了底層的詳細信息,如:掃描的表,表的分區數,文件數以及文件大小等信息,根據這些信息,你可以估算大概的耗時
01階段: 聚合操作SUM並行地在不同的節點上執行
03階段: 將01階段的結果進行傳輸
04階段: 將SUM結果進行合併
02階段: 排序操作並行地在不同的節點中進行
05階段: 排序結果合併,並且輸出
EXPLAIN也會在PROFILE結果的頭部輸出。






SUMMARY命令可以輸出每一階段的耗時,可以快速地瞭解查詢的性能瓶頸,與PROFILE輸出一樣,它只能在查詢之後纔可用,並且顯示實際的時間消耗。SUMMARY輸出也會在PROFILE的頭部輸出的顯示。

select ds,count(*) from t_ed_xxxx_newuser_read_feature_n group by ds order by ds;
summary;
+---------------------+--------+----------+----------+-------+------------+----------+---------------+--------------------------------------------+
| Operator            | #Hosts | Avg Time | Max Time | #Rows | Est. #Rows | Peak Mem | Est. Peak Mem | Detail                                     |
+---------------------+--------+----------+----------+-------+------------+----------+---------------+--------------------------------------------+
| 05:MERGING-EXCHANGE | 1      | 3.20s    | 3.20s    | 372   | 372        | 0 B      | 0 B           | UNPARTITIONED                              |
| 02:SORT             | 51     | 517.22us | 2.54ms   | 372   | 372        | 6.02 MB  | 6.00 MB       |                                            |
| 04:AGGREGATE        | 51     | 1.75ms   | 7.85ms   | 372   | 372        | 2.12 MB  | 10.00 MB      | FINALIZE                                   |
| 03:EXCHANGE         | 51     | 2.91s    | 3.10s    | 2.44K | 372        | 0 B      | 0 B           | HASH(ds)                                   |
| 01:AGGREGATE        | 51     | 135.29ms | 474.62ms | 2.44K | 372        | 2.03 MB  | 10.00 MB      | STREAMING                                  |
| 00:SCAN HDFS        | 51     | 1.08s    | 2.58s    | 2.56K | 96.53M     | 1.05 MB  | 1.00 MB       | default.t_ed_xxxx_newuser_read_feature_n |

PROFILE和SUMMAY區別
profile:輸出底層信息計劃
summary:查看查詢時間及佔用內存
區別不重要,都可用。


除了查詢計劃,可以

  1. 爲數據存儲選擇合適的文件格式(如Parquet),通常對於大數據量來說,Parquet文件格式是最佳
  2. 防止入庫時產生大量的小文件(insert ... values會產生大量小文件,應該避免使用)
    在impala外生成數據時,最好是text格式或Avro,可逐行的構建文件,到impala後再通過簡單的insert ... select語句將其轉換爲Parquet格式.
  3. 根據實際的數據量大小選擇合適的分區粒度
    合適的分區策略可以對數據進行物理拆分,查詢時可以忽略掉無用數據,提高查詢效率,通常建議分區數量在3萬以下(太多的分區也會造成元數據管理的性能下降)
  4. 爲分區key選擇最小的整數類型
    雖然使用string類型也可以作爲分區key,因爲分區key最後都是作爲HDFS目錄使用,但是使用最小的整數類型作爲分區key可以降低內存消耗
  5. 選擇合適的Parquet塊大小
    默認情況下,Impala的insert ... select語句創建的Parquet文件都是每個分區256M(在2.0之後改爲1G),通過Impala寫入的Parquet文件只有一個塊,因而只能被一個機器當作一個單元進行處理。如果在你的Parquet表中只有一個或者幾個分區,或者一個查詢只能訪問一個分區,那麼你的性能會非常慢,因爲沒有足夠的數據來利用Impala併發分佈式查詢的優勢。
  6. 在追求性能或者大數據量查詢時,要先獲取所需要的表的統計指標(如執行compute stats)
  7. 減少傳輸到client端的數據量,如:使用聚合(如 count、sum、max等)、過濾(如WHERE)、LIMIT
    結果集禁止使用美化格式進行展示(在通過impala-shell展示結果時,添加這些可選參數:-B, --output_delimiter)
  8. 選擇合適的join算法

具體地:

  1. 最大的表應該放在表清單的最左邊
  2. 多個join的查詢語句,應該將選擇性最強的join放在最前面
  3. 定期對錶收集統計信息或在大量DML操作後主動收集統計信息
  4. 在單一join查詢中,涉及到的數據表個數儘量不要超過4個,不然效率比較低下

COMPUTE STATS

和HIVE的ANALYZE TABLE類似,這個命令主要也是爲了優化查詢,加快查詢的速度。本來IMPALA是依靠HIVE的ANALYZE TABLE的,但是這個命令不是很好用同時不穩定,所以IMPALA自己實現了個命令完成相同功能。

有兩類,語法:

# 全量
COMPUTE STATS [db_name.]table_name
# 增量
COMPUTE INCREMENTAL STATS [db_name.]table_name [PARTITION (partition_spec)]

作用:
收集有關表中數據的容量和分佈以及所有相關列和分區的信息。這些信息存儲在metastore數據庫中,Impala使用這些信息來幫助優化查詢。
區別:

參考

Impala性能優化總結
Apache Impala 性能優化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章