您好,登錄后才能下訂單哦!
小編給大家分享一下Hive調優的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。例如:SELECT * FROM emp;在這種情況下,Hive可以簡單地讀取emp對應的存儲目錄下的文件,然后輸出查詢結果到控制臺。
在hive-default.xml.template文件中hive.fetch.task.conversion默認是more,老版本hive默認是minimal,該屬性修改為more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
<property> <name>hive.fetch.task.conversion</name> <value>more</value> <description> Expects one of [none, minimal, more]. Some select queries can be converted to single FETCH task minimizing latency. Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), lateral views and joins. 0. none : disable hive.fetch.task.conversion 1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only 2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns) </description> </property>
案例實操:
(1)把hive.fetch.task.conversion設置成none,然后執行查詢語句,都會執行mapreduce程序。 hive (default)> set hive.fetch.task.conversion=none; hive (default)> select * from emp; hive (default)> select ename from emp; hive (default)> select ename from emp limit 3; (2)把hive.fetch.task.conversion設置成more,然后執行查詢語句,如下查詢方式都不會執行mapreduce程序。 hive (default)> set hive.fetch.task.conversion=more; hive (default)> select * from emp; hive (default)> select ename from emp; hive (default)> select ename from emp limit 3;
大多數的Hadoop Job是需要Hadoop提供的完整的可擴展性來處理大數據集的。不過,有時Hive的輸入數據量是非常小的。在這種情況下,為查詢觸發執行任務消耗的時間可能會比實際job的執行時間要多的多。對于大多數這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務。對于小數據集,執行時間可以明顯被縮短。
用戶可以通過設置hive.exec.mode.local.auto的值為true,來讓Hive在適當的時候自動啟動這個優化。
//開啟本地mr set hive.exec.mode.local.auto=true; //設置local mr的最大輸入數據量,當輸入數據量小于這個值時采用local mr的方式 --默認為134217728,即128M set hive.exec.mode.local.auto.inputbytes.max=50000000; //設置local mr的最大輸入文件個數,當輸入文件個數小于這個值時采用local mr的方式 --默認為4 set hive.exec.mode.local.auto.input.files.max=10;
案例實操:
(1)開啟本地模式,并執行查詢語句 hive (default)> set hive.exec.mode.local.auto=true; hive (default)> select * from emp cluster by deptno; Time taken: 1.328 seconds, Fetched: 14 row(s) (2)關閉本地模式,并執行查詢語句 hive (default)> set hive.exec.mode.local.auto=false; hive (default)> select * from emp cluster by deptno; Time taken: 20.09 seconds, Fetched: 14 row(s)
將key相對分散,并且數據量小的表放在join的左邊,這樣可以有效減少內存溢出錯誤發生的幾率;再進一步,可以使用map join讓小的維度表(1000條以下的記錄條數)先進內存。在map端完成reduce。
實際測試發現:新版的hive已經對小表JOIN大表和大表JOIN小表進行了優化。小表放在左邊和右邊已經沒有明顯區別。
有時join超時是因為某些key對應的數據太多,而相同key對應的數據都會發送到相同的reducer上,從而導致內存不夠。此時我們應該仔細分析這些異常的key,很多情況下,這些key對應的數據是異常數據,我們需要在SQL語句中進行過濾。例如key對應的字段為空,操作如下:
案例實操:
(1)配置歷史服務器 配置mapred-site.xml <property> <name>mapreduce.jobhistory.address</name> <value>hadoop102:10020</value> </property> <property> <name>mapreduce.jobhistory.webapp.address</name> <value>hadoop102:19888</value> </property> 啟動歷史服務器 sbin/mr-jobhistory-daemon.sh start historyserver 查看jobhistory http://hadoop102:19888/jobhistory (2)創建空id表 // 創建空id表 create table nullidtable( id bigint, t bigint, uid string, keyword string, url_rank int, click_num int, click_url string ) row format delimited fields terminated by '\t'; (3)加載空id數據到空id表中 load data local inpath '/opt/module/hive/datas/nullid' into table nullidtable; (4)測試不過濾空id insert overwrite table jointable select n.* from nullidtable n left join bigtable o on n.id = o.id; Time taken: 42.038 seconds Time taken: 37.284 seconds (5)測試過濾空id insert overwrite table jointable select n.* from ( select * from nullidtable where id is not null ) n left join bigtable o on n.id = o.id; Time taken: 31.725 seconds Time taken: 28.876 seconds
有時雖然某個key為空對應的數據很多,但是相應的數據不是異常數據,必須要包含在join的結果中,此時我們可以表a中key為空的字段賦一個隨機的值,使得數據隨機均勻地分布到不同的reducer上。例如:
案例實操:
不隨機分布空null值: (1)設置5個reduce個數 set mapreduce.job.reduces = 5; (2)JOIN兩張表 insert overwrite table jointable select n.* from nullidtable n left join bigtable b on n.id = b.id; 結果:如下圖所示,可以看出來,出現了數據傾斜,某些reducer的資源消耗遠大于其他reducer。
隨機分布空null值 (1)設置5個reduce個數 set mapreduce.job.reduces = 5; (2)JOIN兩張表 insert overwrite table jointable select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id; 結果:如下圖所示,可以看出來,消除了數據傾斜,負載均衡reducer的資源消耗
如果不指定MapJoin或者不符合MapJoin的條件,那么Hive解析器會將Join操作轉換成Common Join,即:在Reduce階段完成join。容易發生數據傾斜。可以用MapJoin把小表全部加載到內存在map端進行join,避免reducer處理。
(1)設置自動選擇Mapjoin set hive.auto.convert.join = true; 默認為true (2)大表小表的閾值設置(默認25M以下認為是小表): set hive.mapjoin.smalltable.filesize=25000000;
(1)開啟Mapjoin功能 set hive.auto.convert.join = true; 默認為true (2)執行小表JOIN大表語句 注意:此時小表作為主表,所有數據都要寫出去,因此此時會走reduce,mapjoin失效 insert overwrite table jointable select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url from smalltable s left join bigtable b on s.id = b.id; Time taken: 24.594 seconds (3)執行大表JOIN小表語句 insert overwrite table jointable select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url from bigtable b left join smalltable s on s.id = b.id; Time taken: 24.315 seconds
默認情況下,Map階段同一Key數據分發給一個reduce,當一個key數據過大時就傾斜了。
并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進行部分聚合,最后在Reduce端得出最終結果。
(1)是否在Map端進行聚合,默認為True set hive.map.aggr = true (2)在Map端進行聚合操作的條目數目 set hive.groupby.mapaggr.checkinterval = 100000 (3)有數據傾斜的時候進行負載均衡(默認是false) set hive.groupby.skewindata = true 注意: 當選項設定為 true,生成的查詢計劃會有兩個MR Job。第一個MR Job中,Map的輸出結果會隨機分布 到Reduce中,每個Reduce做部分聚合操作,并輸出結果,這樣處理的結果是相同的Group By Key有可能被 分發到不同的Reduce中,從而達到負載均衡的目的;第二個MR Job再根據預處理的數據結果按照Group By Key分布到Reduce中(這個過程可以保證相同的Group By Key被分布到同一個Reduce中),最后完成最終 的聚合操作。
案例實操:
hive (default)> select deptno from emp group by deptno; Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 23.68 sec HDFS Read: 19987 HDFS Write: 9 SUCCESS Total MapReduce CPU Time Spent: 23 seconds 680 msec OK deptno 10 20 30 ------------------------------------------------------------------------------------- 優化以后 hive (default)> set hive.groupby.skewindata = true; hive (default)> select deptno from emp group by deptno; Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 28.53 sec HDFS Read: 18209 HDFS Write: 534 SUCCESS Stage-Stage-2: Map: 1 Reduce: 5 Cumulative CPU: 38.32 sec HDFS Read: 15014 HDFS Write: 9 SUCCESS Total MapReduce CPU Time Spent: 1 minutes 6 seconds 850 msec OK deptno 10 20 30
數據量小的時候無所謂,數據量大的情況下,由于COUNT DISTINCT操作需要用一個Reduce Task來完成,這一個Reduce需要處理的數據量太大,就會導致整個Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換,但是需要注意group by造成的數據傾斜問題.
案例實操:
(1)創建一張大表 create table bigtable( id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string ) row format delimited fields terminated by '\t'; (2)加載數據 load data local inpath '/opt/module/datas/bigtable' into table bigtable; (3)設置5個reduce個數 set mapreduce.job.reduces = 5; (4)執行去重id查詢 select count(distinct id) from bigtable; Stage-Stage-1: Map: 1 Reduce: 1 Cumulative CPU: 7.12 sec HDFS Read: 120741990 HDFS Write: 7 SUCCESS Total MapReduce CPU Time Spent: 7 seconds 120 msec OK c0 99947 Time taken: 23.607 seconds, Fetched: 1 row(s) (5)采用GROUP by去重id hive (default)> select count(id) from (select id from bigtable group by id) a; Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 17.53 sec HDFS Read: 120752703 HDFS Write: 580 SUCCESS Stage-Stage-2: Map: 1 Reduce: 1 Cumulative CPU: 4.29 sec2 HDFS Read: 9409 HDFS Write: 7 SUCCESS Total MapReduce CPU Time Spent: 21 seconds 820 msec OK _c0 99947 Time taken: 50.795 seconds, Fetched: 1 row(s) 值得說的是: 雖然會多用一個Job來完成,但在數據量大的情況下,這個絕對是值得的。
盡量避免笛卡爾積,join的時候不加on條件,或者無效的on條件,Hive只能使用1個reducer來完成笛卡爾積。
列處理:在SELECT中,只拿需要的列,如果有,盡量使用分區過濾,少用SELECT *。
行處理:在分區剪裁中,當使用外關聯時,如果將副表的過濾條件寫在Where后面,那么就會先全表關聯,之后再過濾,比如:
案例實操:
1)測試先關聯兩張表,再用where條件過濾 select o.id from bigtable b join bigtable o on o.id = b.id where o.id <= 10; Time taken: 34.406 seconds, Fetched: 100 row(s) 2)通過子查詢后,再關聯表 select b.id from bigtable b join ( select id from bigtable where id <= 10 ) o on b.id = o.id; Time taken: 30.058 seconds, Fetched: 100 row(s)
詳見04Hive學習之路(DML數據操作、分區表和分桶表)---2.1、分區表
詳見04Hive學習之路(DML數據操作、分區表和分桶表)---2.2、分桶表
1)通常情況下,作業會通過input的目錄產生一個或者多個map任務。 主要的決定因素有:input的文件總個數,input的文件大小,集群設置的文件塊大小。 2)是不是map數越多越好? 答案是否定的。如果一個任務有很多小文件(遠遠小于塊大小128m),則每個小文件也會被當做一個 塊,用一個map任務來完成,而一個map任務啟動和初始化的時間遠遠大于邏輯處理的時間,就會造成很大的 資源浪費。而且,同時可執行的map數是受限的。 3)是不是保證每個map處理接近128m的文件塊,就高枕無憂了? 答案也是不一定。比如有一個127m的文件,正常會用一個map去完成,但這個文件只有一個或者兩個小 字段,卻有幾千萬的記錄,如果map處理的邏輯比較復雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題2和3,我們需要采取兩種方式來解決:即減少map數和增加map數。
當input的文件都很大,任務邏輯復雜,map執行非常慢的時候,可以考慮增加Map數,來使得每個map處 理的數據量減少,從而提高任務的執行效率。 增加map的方法為:根據 computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M 公式,調整maxSize最大值。讓maxSize最大值低于blocksize就可以增加map的個數。
案例實操:
1)執行查詢 hive (default)> select count(*) from emp; Hadoop job information for Stage-1: number of mappers: 1;number of reducers: 1 2)設置最大切片值為100個字節 hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100; hive (default)> select count(*) from emp; Hadoop job information for Stage-1: number of mappers: 6;number of reducers: 1
1)在map執行前合并小文件,減少map數:CombineHiveInputFormat具有對小文件進行合并的功能 (系統默認的格式)。HiveInputFormat沒有對小文件合并功能。 set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 2)在Map-Reduce的任務結束時合并小文件的設置: //在map-only任務結束時合并小文件,默認true SET hive.merge.mapfiles = true; //在map-reduce任務結束時合并小文件,默認false SET hive.merge.mapredfiles = true; //合并文件的大小,默認256M SET hive.merge.size.per.task = 268435456; //當輸出文件的平均大小小于該值時,啟動一個獨立的map-reduce任務進行文件merge SET hive.merge.smallfiles.avgsize = 16777216;
1)調整reduce個數方法一 ①每個Reduce處理的數據量默認是256MB --hive.exec.reducers.bytes.per.reducer=256000000 ②每個任務最大的reduce數,默認為1009 --hive.exec.reducers.max=1009 ③計算reducer數的公式 --N=min(參數2,總輸入數據量/參數1) 2)調整reduce個數方法二 在hadoop的mapred-default.xml文件中修改 //設置每個job的Reduce個數 set mapreduce.job.reduces = 15; 3)reduce個數并不是越多越好 (1)過多的啟動和初始化reduce也會消耗時間和資源; (2)另外,有多少個reduce,就會有多少個輸出文件,如果生成了很多個小文件,那么如果這些小文件作 為下一個任務的輸入,則也會出現小文件過多的問題; 注意:在設置reduce個數的時候也需要考慮這兩個原則: --處理大數據量利用合適的reduce數; --使單個reduce任務處理數據量大小要合適;
Hive會將一個查詢轉化成一個或者多個階段。這樣的階段可以是MapReduce階段、抽樣階段、合并階段、limit階段。或者Hive執行過程中可能需要的其他階段。默認情況下,Hive一次只會執行一個階段。不過,某個特定的job可能包含眾多的階段,而這些階段可能并非完全互相依賴的,也就是說有些階段是可以并行執行的,這樣可能使得整個job的執行時間縮短。不過,如果有更多的階段可以并行執行,那么job可能就越快完成。
通過設置參數hive.exec.parallel值為true,就可以開啟并發執行。不過,在共享集群中,需要注意下,如果job中并行階段增多,那么集群利用率就會增加。
set hive.exec.parallel=true; //打開任務并行執行,默認為false set hive.exec.parallel.thread.number=16; //同一個sql允許最大并行度,默認為8。
當然,得是在系統資源比較空閑的時候才有優勢,否則,沒資源,并行也起不來。
Hive可以通過設置防止一些危險操作: 1)分區表不使用分區過濾 將hive.strict.checks.no.partition.filter設置為true時,對于分區表,除非where語句中含有 分區字段過濾條件來限制范圍,否則不允許執行。換句話說,就是用戶不允許掃描所有分區。進行這個限制 的原因是,通常分區表都擁有非常大的數據集,而且數據增加迅速。沒有進行分區限制的查詢可能會消耗令 人不可接受的巨大資源來處理這個表。 2)使用order by沒有limit過濾 將hive.strict.checks.orderby.no.limit設置為true時,對于使用了order by語句的查詢,要求 必須使用limit語句。因為order by為了執行排序過程會將所有的結果數據分發到同一個Reducer中進行處 理,強制要求用戶增加這個LIMIT語句可以防止Reducer額外執行很長一段時間。 3)笛卡爾積 將hive.strict.checks.cartesian.product設置為true時,會限制笛卡爾積的查詢。對關系型數據 庫非常了解的用戶可能期望在 執行JOIN查詢的時候不使用ON語句而是使用where語句,這樣關系數據庫的執 行優化器就可以高效地將WHERE語句轉化成那個ON語句。不幸的是,Hive并不會執行這種優化,因此,如果 表足夠大,那么這個查詢就會出現不可控的情況。
JVM重用是Hadoop調優參數的內容,其對Hive的性能具有非常大的影響,特別是對于很難避免小文件的場景或task特別多的場景,這類場景大多數執行時間都很短。
Hadoop的默認配置通常是使用派生JVM來執行map和Reduce任務的。這時JVM的啟動過程可能會造成相當大的開銷,尤其是執行的job包含有成百上千task任務的情況。JVM重用可以使得JVM實例在同一個job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中進行配置。通常在10-20之間,具體多少需要根據具體業務場景測試得出。
<property> <name>mapreduce.job.jvm.numtasks</name> <value>10</value> <description>How many tasks to run per jvm. If set to -1, there is no limit. </description> </property>
這個功能的缺點是,開啟JVM重用將一直占用使用到的task插槽,以便進行重用,直到任務完成后才能釋放。如果某個“不平衡的”job中有某幾個reduce task執行的時間要比其他Reduce task消耗的時間多的多的話,那么保留的插槽就會一直空閑著卻無法被其他的job使用,直到所有的task都結束了才會釋放。
詳見07Hive學習之路(壓縮和存儲)
1)基本語法
EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query
2)案例實操:
①查看下面這條語句的執行計劃 explain select * from emp; explain select deptno, avg(sal) avg_sal from emp group by deptno; ②查看詳細執行計劃 explain extended select * from emp; explain extended select deptno, avg(sal) avg_sal from emp group by deptno;
以上是“Hive調優的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。