概述
基於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算法有兩類:
- hash join:對於等值join,Impala將採用hash的方式處理,具體又分兩種策略:broadcast 和 Shuffle。
- broadcast join 非常適合右表是小表的情形,Impala先將右表複製到各個節點,再和左表做join
- shuffle join:亦partitioned join,適合大表和大表關聯。partitioned join 和右表的 partition 沒有直接關係,Impala會將右表打散成N份,發送到左表所在的節點,然後join;有點類似於mapreduce中的shuffle
- 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)
區別:
- 內部表的數據是由Hive自身管理的,外部表的數據是由HDFS管理的;
- 刪除內部表會刪除存儲在hive元數據庫的元數據和存儲在HDFS的文件數據;刪除外部表只刪除元數據不刪除存儲的數據;
- 兩者都可以在建表的時候指定location,指定數據文件的存放位置;如果不指定的話,默認都是在
/user/hive/warehouse/目錄
下(這個目錄是可以在配置文件中修改的)。 - 兩者的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提供三種方式得知查詢計劃
- EXPLAIN:獲取執行計劃,而無須真正的執行query
- PROFILE:產生一個關於最近一次查詢的底層報告的詳細信息展示。與EXPLAIN不同,這些信息只在查詢完成之後纔會生成,它顯示每個節點上的物理詳細信息如:讀取的字節數,最大內存消耗等。
想要查看一個查詢的物理性能特性的概覽,可以在執行查詢之後立馬在impala-shell中執行PROFILE命令,輸出的信息中將展示哪個階段耗時最多,以及每一階段估算的內存消耗、行數與實際的差異。進行性能分析,可根據這些信息來確定查詢時I/O密集型,還是CPU密集型,網絡是否導致瓶頸,是否某些節點性能差但是其它節點性能好等信息。 - 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:查看查詢時間及佔用內存
區別不重要,都可用。
除了查詢計劃,可以
- 爲數據存儲選擇合適的文件格式(如Parquet),通常對於大數據量來說,Parquet文件格式是最佳
- 防止入庫時產生大量的小文件(
insert ... values
會產生大量小文件,應該避免使用)
在impala外生成數據時,最好是text格式或Avro,可逐行的構建文件,到impala後再通過簡單的insert ... select
語句將其轉換爲Parquet格式. - 根據實際的數據量大小選擇合適的分區粒度
合適的分區策略可以對數據進行物理拆分,查詢時可以忽略掉無用數據,提高查詢效率,通常建議分區數量在3萬以下(太多的分區也會造成元數據管理的性能下降) - 爲分區key選擇最小的整數類型
雖然使用string類型也可以作爲分區key,因爲分區key最後都是作爲HDFS目錄使用,但是使用最小的整數類型作爲分區key可以降低內存消耗 - 選擇合適的Parquet塊大小
默認情況下,Impala的insert ... select
語句創建的Parquet文件都是每個分區256M(在2.0之後改爲1G),通過Impala寫入的Parquet文件只有一個塊,因而只能被一個機器當作一個單元進行處理。如果在你的Parquet表中只有一個或者幾個分區,或者一個查詢只能訪問一個分區,那麼你的性能會非常慢,因爲沒有足夠的數據來利用Impala併發分佈式查詢的優勢。 - 在追求性能或者大數據量查詢時,要先獲取所需要的表的統計指標(如執行
compute stats
) - 減少傳輸到client端的數據量,如:使用聚合(如 count、sum、max等)、過濾(如WHERE)、LIMIT
結果集禁止使用美化格式進行展示(在通過impala-shell展示結果時,添加這些可選參數:-B, --output_delimiter
) - 選擇合適的join算法
具體地:
- 最大的表應該放在表清單的最左邊
- 多個join的查詢語句,應該將選擇性最強的join放在最前面
- 定期對錶收集統計信息或在大量DML操作後主動收集統計信息
- 在單一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使用這些信息來幫助優化查詢。
區別: