==========================
理解 mem_limit 參數
==========================
set mem_limit=-1b #取消內存限制
set mem_limit=1gb #設置單機內存上限為1GB, 注意是單機
set mem_limit=1mb #設置單機內存上限為1MB, 注意是單機
如果設置了 mem_limit, impala 將跳過Query內存評估環節, 直接檢查Pool中剩余內存是否夠用, 如果夠用的話, 將直接執行. 如果不夠用的話, 將按照pool設定的策略, 將Query放到queue隊列中, 如果在timeout設定時間內仍得不到足量的內存資源, 該Query將被取消. 如果用戶不設置mem_limit, 默認使用Pool的 default_pool_mem_limit 值, 如果default_pool_mem_limit沒有設置,Impala會自己來估計這個值. 如果沒有設置mem_limit, 否則Impala根據統計信息和執行計划預估內存消耗.
當然, 在運行期間, 如果Query占用的內存超過 mem_limit, impala 將終止該 query,
假設單機設置了10GB的內存上線, 集群有10個節點, 在查詢之前, Impala檢查Pool 中剩余內存是否夠300GB.
Impala pool 級別幾個設置參數有:
default_pool_max_queued, 進入等待隊列中查詢的缺省個數
default_pool_max_requests, 正在執行中的查詢個數
default_pool_mem_limit, 為查詢設置的默認內存占用上限, 通常通過 disable_pool_mem_limits 參數禁用了該設置.
queue_wait_timeout_ms, 缺省 60000 毫秒, 即1分鍾, 查詢在隊列中最大等待時長, 超過該設定值, 查詢就被reject.
手工設置 MEM_LIMIT 參數的必要性
1. 避免Impala的 over-estimation 的不良后果
Impala 在查詢執行之前會預測SQL執行會消耗多大內存, 預測主要是依據表的統計信息, 但在很多時候, Impala的預估是很粗放式的, 即使表的統計信息很及時, impala也會over estimate內存消耗. over-estimation 的后果有: (1)預估值如果大於impala pool中的剩余內存, impala 就會reject該查詢. (2)降低並發度.
2. 有可能會提升執行速度
手工設定 MEM_LIMIT 參數后, Impala將會跳過內存預測過程, 有可能會加快執行速度.
如何設置 MEM_LIMIT 參數?
先試運行一下SQL, 然后在 profile 中, 查看其 memory_per_node_peak 值, 該值即為實際上的內存消耗, 或者在 impala WebUI該query詳細頁面的 Summary 頁簽的 Peak Mem 欄位.
==========================
impala 資源的軟隔離
==========================
摘自國雙公司的說明: https://blog.csdn.net/qq_18882219/article/details/78447558
由於Impala的每個Impalad節點都可以接受查詢,對於每個Pool現在有多少查詢,占了多少內存,Queue了多少,這些信息也是每個Impalad更新,通過Statestored來廣播到其他Impalad,所以這個信息可能在每個節點上可能是不一致的。當一個Impalad收到查詢需要做一些決策例如是否拒絕,是否Queue住,本地的這個決策信息可能是舊的,所以Impala基於Pool的資源隔離本身來說是一種軟隔離,也就是說對於任何一個Pool來說,其用到的內存有可能會超過最大內存,運行的查詢數量有可能會超過Pool設置的最大查詢數量。這個我們在實際的使用中也證明了。軟隔離問題會帶來兩個風險:
1.單個節點申請的內存在某個時刻超過了分配給Impalad進程的內存,這個會導致Impalad OOM退出
2.某個Pool在某一個時刻使用了遠遠超過這個Pool的資源,這個對於不同業務用Pool來做資源隔離是不利的。
這個問題我們也跟Impala社區的開發者做過討論,最后使用的方案是:單個Pool指定唯一的Coordinator,這個Pool的所有查詢都發送給同一個Impalad。於是這個Coordinator時刻都有這個資源池最新的信息,就從軟隔離進化成了硬隔離,缺點是會帶來單點問題,可采取了主備的方式來避免這一問題.
==========================
其他幾個重要的session 變量
==========================
除了 MEM_LIMIT, 還有如下常用的session 變量
EXPLAIN_LEVEL :設置explain和profile的輸出詳略
DISABLE_UNSAFE_SPILLS : 是否禁用 disk spill, 目前對disk spill限制還很多, 比如非等值join不能使用 disk spill.
REQUEST_POOL : 設置所在的隊列
EXPLAIN_LEVEL 參數可以控制 explain語句的輸出, 也可以控制 profile 命令輸出. 需要說明的是, explain 可以在SQL客戶端中執行, 而profile 命令只能在impala shell中執行, 另外只能展現已經最近執行完畢的那個SQL的profile.
set EXPLAIN_LEVEL = 0 -- 0 or MINIMAL, 因為輸出信息較少, 更容易發現主要的信息 比如join的order
set EXPLAIN_LEVEL = 1 -- 1 or STANDARD, 標准的輸出
set EXPLAIN_LEVEL = 2 -- 2 or EXTENDED, 詳細的輸出
set EXPLAIN_LEVEL = 3 # 3 or VERBOSE, 更詳細的輸出
如果查詢速度較差, 可以通過下面命令看看是否缺少統計信息.
set explain_level=3 --verbose 級, 包含更多的細節信息. 在explain輸出中, 如果有如下信息, 則對應表沒有統計信息.
cardinality: unavailable
table stats: unavailable
column stats: unavailable
==========================
Join reordering
==========================
對於多表Join 查詢, 老版的impala總是按照表出現的順序依次查詢, 但新版Impala執行引擎已經可以自動按照的表/列的統計信息, 做Join reordering. 規則是:
大表(表 size和distinct value多的表)先被查詢, 小表后被查詢
無統計信息的表(impala認為表的size為0)將最后被查詢.
==========================
使用 STRAIGHT_JOIN Hint
==========================
當統計信息過期或沒有統計信息或者表有很詭異的數據分布, Impala執行計划的查詢表順序很可能不是最優, 這時候, 最好加上 STRAIGHT_JOIN Hint, 強制impala按照SQL中表出現的次序做查詢, 當然我們SQL表出現次序應該是精心調整過的.
另外, STRAIGHT_JOIN 僅僅對於當前Select 語句有效, 如果子查詢和view也需要嚴格按照表次序做查詢, 需要在子查詢和視圖中顯式地加上 STRAIGHT_JOIN hint, 另外 STRAIGHT_JOIN hint 是impala 的關鍵詞, 不能放在/*+*/中.
select STRAIGHT_JOIN t1.* from t1
join t2 on t1.id=t2.id
select distinct STRAIGHT_JOIN t2.id,t1.name from t1
join t2 on t1.id=t2.id
;
==========================
join 的算法
==========================
1. hash join: 對於等值join, impala將采用hash的方式處理, 具體又分兩種策略, broadcast 和 Shuffle.
broadcast join 非常適合右表是小表的情形, impala 先將右表復制到各個節點, 再和左表做join.
shuffle join, 也叫做partitioned join, 適合大表和大表關聯. 注意 partitioned join 和右表的 partition 沒有直接關系, impala 會將右表打散成N份, 發送到左表所在的節點, 然后作join.
2. nested loop join: 針對非等值join, impala將使用 nested loop join, 這時我們不能設置 SHUFFLE/BROADCAST hint, 也不能使用 spill disk 功能. impala的非等值join的效率較低, Vertica的效率非常高, Hive直接不支持.
SELECT STRAIGHT_JOIN select_list FROM
join_left_hand_table
JOIN [{ /* +BROADCAST */ | /* +SHUFFLE */ }]
join_right_hand_table
remainder_of_query;
/* +SHUFFLE */ 即 partitioned join, 是將要關聯的兩個表按照
/* +BROADCAST */ 即
Exchange : the intermediate results are transmitted back to the coordinator node (labelled here as the EXCHANGE node)
==========================
最佳實踐
==========================
Impala執行引擎還不是那么智能, 多表join 的SQL最好還是按照下面的推薦的寫法:
1. 最大的表應該放在表清單的最左邊.
2. 多個join的查詢語句, 應該將選擇性最強的join放在最前面.
3. 定期對表收集統計信息, 或者在大量DML操作后主動收集統計信息.
4. 在一個單一的查詢里面, 參加join的表個數盡量不要超過4個, 不然效率比較低下.
