Hive 的優化
原始語句: select count(distinct ip) from (select ip as ip from comprehensive.f_client_boot_daily where year="2013" and month="10" union all select pub_ip as ip from f_app_boot_daily where year="2013" and month="10" union all select ip as ip from format_log.format_pv1 where year="2013" and month="10" and url_first_id=1 ) d
原因: select ip as ip from comprehensive.f_client_boot_daily where year="2013" and month="10"這個語句篩選出來的資料約有10億條,select pub_ip as ip from f_app_boot_daily where year="2013" and month="10"約有10億條條,select ip as ip from format_log.format_pv1 where year="2013" and month="10" and url_first_id=1 篩選出來的資料約有10億條,總的資料量大約30億條。這麼大的資料量,使用disticnt函式,所有的資料只會shuffle到一個reducer上,導致reducer資料傾斜嚴重
優化後的語句: select count(*) from (select ip from (select ip as ip from comprehensive.f_client_boot_daily where year="2013" and month="10" union all select pub_ip as ip from f_app_boot_daily where year="2013" and month="10" union all select ip as ip from format_log.format_pv1 where year="2013" and month="10" and url_first_id=1 ) d group by ip ) b
2、 join 優化:
生 成一個job: 多表連線,如果多個表中每個表都使用同一個列進行連線(出現在JOIN子句中),則只會生成一個MR Job,例如:
1 |
SELECT a.val, b.val, c.val FROM a JOIN b ON (a. key = b.key1) JOIN c ON (c. key = b.key1) |
三個表a、b、c都分別使用了同一個欄位進行連線,亦即同一個欄位同時出現在兩個JOIN子句中,從而只生成一個MR Job。
生成多個job:
多表連線,如果多表中,其中存在一個表使用了至少2個欄位進行連線(同一個表的至少2個列出現在JOIN子句中),則會至少生成2個MR Job,例如:
1 |
SELECT a.val, b.val, c.val FROM a JOIN b ON (a. key = b.key1) JOIN c ON (c. key = b.key2) |
三個表基於2個欄位進行連線,這兩個欄位b.key1和b.key2同時出現在b表中。連線的過程是這樣的:首先a和b表基於a.key和b.key1進行連線,對應著第一個MR Job;表a和b連線的結果,再和c進行連線,對應著第二個MR Job。 3、表連線順序優化: 多表連線,資料量大的表放後面。
1 |
SELECT a.val, b.val, c.val FROM a JOIN b ON (a. key = b.key1) JOIN c ON (c. key = b.key1) |
這個JOIN語句,會生成一個MR Job,在選擇JOIN順序的時候,資料量相比應該是b < c,表a和b基於a.key = b.key1進行連線,得到的結果(基於a和b進行連線的Key)會在Reducer上快取在buffer中,在與c進行連線時,從buffer中讀取Key(a.key=b.key1)來與表c的c.key進行連線。
另外,也可以通過給出一些Hint資訊來啟發JOIN操作,這指定了將哪個表作為大表,從而得到優化。例如:
1 |
SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a. key = b.key1) JOIN c ON (c. key = b.key1) |
4、 基於條件的LEFT OUTER JOIN優化
左連線時,左表中出現的JOIN欄位都保留,右表沒有連線上的都為空。對於帶WHERE條件的JOIN語句,例如:
1 |
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a. key =b. key ) |
2 |
WHERE a.ds= '2009-07-07' AND b.ds= '2009-07-07' |
執行順序是,首先完成2表JOIN,然後再通過WHERE條件進行過濾,這樣在JOIN過程中可能會輸出大量結果,再對這些結果進行過濾,比較耗時。可以進行優化,將WHERE條件放在ON後,例如:
1 |
SELECT a.val, b.val FROM a LEFT OUTER JOIN b |
2 |
ON (a. key =b. key AND b.ds= '2009-07-07' AND a.ds= '2009-07-07' ) |
5、左半連線
左半連線(LEFT SEMI JOIN)
左半連線實現了類似IN/EXISTS的查詢語義,使用關係資料庫子查詢的方式實現查詢SQL,例如:
1 |
SELECT a. key , a.value FROM a WHERE a. key IN ( SELECT b. key FROM b); |
使用Hive對應於如下語句:
1 |
SELECT a. key , a.val FROM a LEFT SEMI JOIN b ON (a. key = b. key ) |
需要注意的是,在LEFT SEMI JOIN中,表b只能出現在ON子句後面,不能夠出現在SELECT和WHERE子句中。
關於子查詢,這裡提一下,Hive支援情況如下:
- 在0.12版本,只支援FROM子句中的子查詢;
- 在0.13版本,也支援WHERE子句中的子查詢。
6、
Map Side JOIN
Map Side JOIN優化的出發點是,Map任務輸出後,不需要將資料拷貝到Reducer節點,降低的資料在網路節點之間傳輸的開銷。
多表連線,如果只有一個表比較大,其他表都很小,則JOIN操作會轉換成一個只包含Map的Job,例如:
1 |
SELECT /*+ MAPJOIN(b) */ a.
|