1.Hive數據傾斜問題。
數據傾斜:數據傾斜主要表現在,map/reduce程序執行時,reduce節點大部分執行完畢,但是有一個或者幾個reduce節點運行很慢,導致整個程序的處理時間很長,這是因為某一個key的條數比其他key多很多(有時是百倍或者千倍之多),這條Key所在的reduce節點所處理的數據量比其他節點就大很多,從而導致某幾個節點遲遲運行不完。
產生原因:1)key分布不均勻
2)業務數據本身的特性
3)SQL語句造成數據傾斜
表現:任務進度長時間維持在99%(或100%),查看任務監控頁面,發現只有少量(1個或幾個)reduce子任務未完成。因為其處理的數據量和其他reduce差異過大,單一reduce的記錄數與平均記錄數差異過大,通常可能達到3倍甚至更多, 最長時長大於平均時長。
產生數據傾斜的業務場景及解決辦法:
1)空值產生的數據傾斜
在日志中,常會有信息丟失的問題,比如日志中的 user_id,如果取其中的 user_id 和用戶表中的 user_id 相關聯,就會碰到數據傾斜的問題。
解決方案 1:user_id 為空的不參與關聯
select * from log a join user b on a.user_id is not null and a.user_id = b.user_id
- 1
解決方案 2: 賦予空值新的 key 值
select * from log a left outer join user b on case when a.user_id is null then concat('hive',rand()) else a.user_id end = b.user_id
- 1
- 2
把空值的 key 變成一個字符串加上一個隨機數,就能把造成數據傾斜的數據分到不同的 reduce 上解決數據傾斜的問題。
2)不同數據類型關聯產生數據傾斜
用戶表中 user_id 字段為 int,log 表中 user_id 為既有 string 也有 int 的類型, 當按照兩個表的 user_id 進行 join 操作的時候,默認的 hash 操作會按照 int 類型的 id 進行分配,這樣就會導致所有的 string 類型的 id 就被分到同一個 reducer 當中。
解決方案:轉換為相同數據類型
select * from user a left outer join log b on b.user_id = cast(a.user_id as string)
- 1
3)大小表關聯查詢產生數據傾斜
使用map join讓小的維度表(1000條以下的記錄條數)先進內存。在map端完成進行join操作。 ---看到
map join 概念:將其中做連接的小表(全量數據)分發到所有 MapTask 端進行 Join,從而避免了 reduceTask,前提要求是內存足以裝下該全量數據
map join使用限制:必須是join中從表(子查詢)數據比較小。所謂從表,即左外連接的右表,或者右外連接的左表。
map join的適用場景:如關聯操作中有一張表非常小,不等值的連接操作。通過上面分析你會發現,並不是所有的場景都適合用MapJoin,它通常會用在如下的一些情景:在兩個要連接的表中,有一個很大,有一個很小,這個小表可以存放在內存中而不影響性能。這樣我們就把小表文件復制到每一個Map任務的本地,再讓Map把文件讀到內存中待用。
在 hive 中,直接提供了能夠在 HQL 語句指定該次查詢使用 map join.
首先設置map join:
set hive.auto.convert.join= true;//設置mapjoin
- 1
在 hive0.11 版本以后會自動開啟 map join 優化,由兩個參數控制:
set hive.auto.convert.join=true; //設置 MapJoin 優化自動開啟 set hive.mapjoin.smalltable.filesize=25000000 //設置小表不超過多大時開啟 mapjoin 優化
- 1
- 2
map join 的用法是在查詢/子查詢的SELECT關鍵字后面添加/ * + MAPJOIN(tablelist) * /提示優化器轉化為map join。
詳細舉例如下:join操作一般都是在reduce階段完成的,寫sql的時候要注意把小表放在join的左邊,原因是在 Join 操作的 Reduce 階段,位於 Join 操作符左邊的表的內容會被加載進內存,將條目少的表放在左邊,可以有效減少發生 out of memory 錯誤的幾率。 一個大表和一個配置表的reduce join經常會引起計算不均衡的情況。比如配置表gender_config(gender string,gender_id int)。把“男”“女”字符串映射成一個id。配置表和上面的user表join的sql如下: select user.id , gender_config.gender_id from gender_config join user on gender_config.gender=user.gender。gender 只有男女兩個值,hive處理join的時候把join_key作為reduce_key,因此會出現和group by類似的reduce計算不均衡現象,只有兩個reduce參與計算,每個reduce計算100億條記錄。
這種大表和配置表通常采用map join的方式來解決這種不均衡的現象。目前hive是采用/ * + MAPJOIN(gender_config) * /提示的方式告訴翻譯器把sql翻譯成mapjoin,提示里必須指明配置表是哪個。 select /*+ MAPJOIN(gender_config) */ user.id , gender_config.gender_id from gender_config join user on gender_config.gender=user.gender
4)小文件過多:
當出現小文件過多,需要合並小文件。解決方法:set hive.merge.mapfiles=true
1>hive.map.aggr=true:map端部分聚合。
set hive.map.aggr=true //map端部分聚合,相當於Combiner,可以減小壓力(默認開啟)
- 1
例: 先看看下面這條SQL:select user.gender,count(1) from user group by user.gende。由於用戶的性別只有男和女兩個值 (未知)。如果沒有map端的部分聚合優化,map直接把groupby_key 當作reduce_key發送給reduce做聚合,就會導致計算不均衡的現象。雖然map有100萬個,但是reduce只有兩個在做聚合,每個reduce處理100億條記錄。
沒開map端聚合產生的計算不均衡現象
hive.map.aggr=true參數控制在group by的時候是否map局部聚合,這個參數默認是打開的。參數打開后的計算過程如下圖。由於map端已經做了局部聚合,雖然還是只有兩個reduce做最后的聚合,但是每個reduce只用處理100萬行記錄,相對優化前的100億小了1萬。
2>開啟數據傾斜時負載均衡
set hive.groupby.skewindata=true//默認關閉
- 1
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.groupby.skewindata=true:通常這種情況都是在有distinct出現的時候,比如下面的sql: select user.gender,count(distinct user.id) from user group by user.gender ,由於map需要保存所有的user.id , map聚合開關會自動關掉,導致出現計算不均衡的現象,只有2個redcue做聚合,每個reduce處理100億條記錄。
hive.groupby.skewindata =true參數會把上面的sql翻譯成兩個MR,第一個MR的reduce_key是gender+id。因為id是一個隨機散列的值,因此這個MR的reduce計算是很均勻的,reduce完成局部聚合的工作:
MR1第二個MR完成最終的聚合,統計男女的distinct id值,數據流如下圖所示,每個Map只輸出兩條記錄,因此雖然只有兩個redcue計算也沒有關系,絕大部分計算量已經在第一個MR完成
MR2 hive.groupby.skewindata 默認是關閉的,因此如果確定有不均衡的情況,需要手動打開這個開關。當然,並不是所有的有distinct的group by都需要打開這個開關,比如下面的sql:
select id,count (distinct gender) from user group by user.id
select gender,count (distinct id) from user group by user.gender
因為user.id是一個散列的值,因此已經是計算均衡的了,所有的reduce都會均勻計算。只有在group by_key不散列,而distinct_key散列的情況下才需要打開這個開關,其他的情況map聚合優化就足矣。
5)當HiveQL中包含count(distinct)
采用 sum() group by 的方式來替換 count(distinct)完成計算。
2.Hive中的排序關鍵字有哪些?
sort by ,order by ,distribute by,cluster by
sort by :不是全局排序,對每個reduce內部數據進行排序,對於全局數據結果來說不是排序的。
order by :會對輸入做全局排序,因此只有一個reducer(多個reducer無法保證全局有序)。只有一個reducer,會導致當輸入規模較大時,需要較長的計算時間。
distribute by :指定分區(這里的分區指的是map reduce過程中的分區),按照指定的字段對數據進行划分輸出到不同的reduce中,通常結合sort by使用(注:distribute by必須在sort by之前)。
cluster by :屬於distribute by和sort by的組合。當distribute by 和sort by的字段相同時,等同於cluster by,使用cluster by進行替代。
3.hive有哪些方式保存元數據,各有哪些特點?
1)內嵌模式:將元數據保存在本地內嵌的derby數據庫中,內嵌的derby數據庫每次只能訪問一個數據文件,也就意味着它不支持多會話連接。
2)本地模式:將元數據保存在本地獨立的數據庫中(一般是mysql),這可以支持多會話連接。
3)遠程模式:把元數據保存在遠程獨立的mysql數據庫中,避免每個客戶端都去安裝mysql數據庫。
Metastore作用:
metadata即元數據,元數據包含用Hive創建的database、tabel等的元信息。元數據存儲在關系型數據庫中。如Derby、MySQL等。
Metastore的作用是:客戶端連接metastore服務,metastore再去連接MySQL數據庫來存取元數據。有了metastore服務,就可以有多個客戶端同時連接,而且這些客戶端不需要知道MySQL數據庫的用戶名和密碼,只需要連接metastore 服務即可。
三種配置方式區別:
內嵌模式使用的是內嵌的Derby數據庫來存儲元數據,也不需要額外起Metastore服務。這個是默認的,配置簡單,但是一次只能一個客戶端連接,適用於用來實驗,不適用於生產環境。
本地元存儲和遠程元存儲都采用外部數據庫來存儲元數據,目前支持的數據庫有:MySQL、Postgres、Oracle、MS SQL Server。
本地元存儲和遠程元存儲的區別是:本地元存儲不需要單獨起metastore服務,用的是跟hive在同一個進程里的metastore服務。遠程元存儲需要單獨起metastore服務,然后每個客戶端都在配置文件里配置連接到該metastore服務。遠程元存儲的metastore服務和hive運行在不同的進程。
4.海量數據分布在100台電腦中,想個辦法高效統計出這批數據的TOP10。
方案1:
1)在每台電腦上求出TOP10,可以采用包含10個元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。
2)比如求TOP10大,我們首先取前10個元素調整成最小堆,如果發現,然后掃描后面的數據,並與堆頂元素比較,如果比堆頂元素大,那么用該元素替換堆頂,然后再調整為最小堆。
3)最后堆中的元素就是TOP10大。
方案2:
1)求出每台電腦上的TOP10后,然后把這100台電腦上的TOP10組合起來,共1000個數據
2)再利用上面類似的方法求出TOP10就可以了。
4.Hive中追加導入數據的4種方式是什么?請寫出簡要語法
從本地導入:load data local inpath ‘/home/1.txt’ (overwrite)into table student;
從Hdfs導入:load data inpath ‘/user/hive/warehouse/1.txt’ (overwrite)into table student;
查詢導入:create table student1 as select * from student;(也可以具體查詢某項數據)
查詢結果導入:insert(overwrite)into table staff select * from track_log;
5.Hive導出數據有幾種方式?如何導出數據?
1.用insert overwrite導出方式
1)導出到本地:
insert overwrite local directory ‘/home/test/1’ row format delimited fields terminated by ‘\t’ select * from staff;(遞歸創建目錄)
2)導出到HDFS
insert overwrite directory ‘/user/hive/1/2’ row format delimited fields terminated by ‘\t’ select * from staff;
2.Bash shell覆蓋追加導出
例如:$ bin/hive -e ‘select * from staff;’ > /home/export/backup.log
3.Sqoop把hive數據導出到外部
6.hive 內部表和外部表區別?
1)內部表:默認創建的表都是所謂的管理表,有時也被稱為內部表。因為這種表Hive會或多或少地控制着數據的生命周期。Hive默認情況下會將這些表的數據存儲在由配置 hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定義的目錄的子目錄下。 當我們刪除一個管理表時,Hive也會刪除這個表中數據。管理表不適合和其他工具共享數據。
2)外部表:因為表是外部表,所以Hive並非認為其完全擁有這份數據。刪除該表並不會刪除掉這份數據,不過描述表的元數據信息會被刪除掉。
下面以一個具體的例子說明內部表與外部表的區別。
首先,創建一個外部表:
將abc.txt中的數據加載到表中。
在hdfs上可查到
之后刪除此外部表
查詢所有表發現確實沒有此表
但在hdfs上此表仍然存在
此時,數據在,但表已刪除
如果將刪除了的表再次創建
查詢表中的數據,表不為空
說明元數據與實際數據誰先有都可以,可以先在hdfs上存儲元數據,再創建表;也可以先創建表,再存儲元數據。
接下來創建一個內部表:
將abc.txt導入此表
在hdfs上查看
刪除此表
在hdfs上查看,此表不存在
由此可見內部表與外部表的區別:內部表刪除后,hdfs上的元數據一並刪除,而外部表刪除后,hdfs上的元數據並未刪除。
管理表和外部表的使用場景:
每天將收集到的網站日志定期流入HDFS文本文件。在外部表(原始日志表)的基礎上做大量的統計分析,用到的中間表、結果表使用內部表存儲,數據通過SELECT+INSERT進入內部表。
3.管理表與外部表的互相轉換
1)查詢表的類型
2)修改為內部表
3)再次查詢表的類型
若將內部表改為外部表,則為’EXTERNAL’='TRUE
注:‘EXTERNAL’=‘TRUE’和’EXTERNAL’='FALSE’為固定寫法,區分大小寫!
7 分區和分桶的區別?
分區:
指按照數據表的某列或某些列分為多個區,區從形式上可以理解為文件夾,比如我們要收集某個大型網站的日志數據,一個網站每天的日志數據存在同一張表上,由於每天會生成大量的日志,導致數據表的內容巨大,在查詢時進行全表掃描耗費的資源非常多。那其實這個情況下,我們可以按照日期對數據表進行分區,不同日期的數據存放在不同的分區,在查詢時只要指定分區字段的值就可以直接從該分區查找。
分桶:
分桶是相對分區進行更細粒度的划分。分桶將整個數據內容按照某列屬性值得hash值進行區分,如要按照name屬性分為3個桶,就是對name屬性值的hash值對3取摸,按照取模結果對數據分桶:取模結果為0的數據記錄存放到一個文件,取模為1的數據存放到一個文件,取模為2的數據存放到一個文件。
8.Hive優化
1)限制調整:
LIMIT語句是大家經常使用到的,經常使用CLI的用戶都會使用到。不過,在很多情況下LIMIT語句還是需要執行整個查詢語句,然后再返回部分結果的。因為這種情況通常是浪費的,所以應該盡可能地避免出現這種情況。Hive有-一個配置屬性可以開啟,當使用LIMTI語句時,其可以對源數據進行抽樣:
一旦屬性hive.limit.optimize.enable的值設置為true,那么還會有兩個參數可以控制這個操作,也就是hive.limit.row.max.size 和hive.limit.optimize.limit.file:
這個功能的-一個缺點就是,有可能輸人中有用的數據永遠不會被處理到,例如,像任意的一個需要reduce步驟的查詢,JOIN 和GROUP BY操作,以及聚合函數的大多數調用,等等,將會產生很不同的結果。也許這個差異在很多情況下是可以接受的,但是重要的是要理解。
2)Join優化:
1>每個ON子句使用同一個連接鍵。當對3個或者更多個表進行JOIN連接時,如果每個ON子句都使用相同的連接鍵的話,那么只會產生一個MapReduce job。
2>Hive同時假定查詢中最后一個表是最大的那個表。在對每行記錄進行連接操作時,它會嘗試將其他表緩存起來,然后掃描最后那個表進行計算。因此,用戶需要保證連續查詢中的表的大小從左到右是依次增加的。或者使用Hive提供的“標記”機制來顯式地告之查詢優化器哪張表是大表,使用方式如下:
現在Hive將會嘗試將表stocks 作為驅動表,即使其在查詢中不是位於最后面的。
3>map-side join:如果所有表中只有一張表是小表,那么可以在最大的表通過mapper的時候將小表完全放到內存中。Hive可以在map端執行連接過程(稱為map-side JOIN),這是因為Hive可以和內存中的小表進行逐一匹配,從而省略掉常規連接操作所需要的reduce過程。即使對於很小的數據集,這個優化也明顯地要快於常規的連接操作。其不僅減少了reduce過程,而且有時還可以同時減少map過程的執行步驟。
在Hive v0.7之前的版本中,如果想使用這個優化,需要在查詢語句中增加一個標記來進行觸發。如下面的這個內連接(INNER JOIN)的例子所示:
從Hive v0.7 版本開始,廢棄了這種標記的方式,不過如果增加了這個標記同樣是有效的。如果不加上這個標記,那么這時用戶需要設置屬性hive.auto.convertJOIN 的值為true, 這樣Hive才會在必要的時候啟動這個優化。默認情況下這個屬性的值是false。
需要注意的是,用戶也可以配置能夠使用這個優化的小表的大小。如下是這個屬性的默認值(單位是字節):
如果用戶期望Hive在必要的時候自動啟動這個優化的話,那么可以將這-一個(或兩個)屬性設置在SHOME/.hiverc文件中。Hive對於右外連接(RIGHT OUTER JOIN)和全外連接(FULL OUTER JOIN)不支持這個優化。
3)本地模式:
大多數的Hadoop Job是需要Hadoop提供的完整的可擴展性來處理大數據集的。不過,有時Hive的輸人數據量是非常小的。在這種情況下,為查詢觸發執行任務的時間消耗可能會比實際job的執行時間要多得多。對於大多數這種情況,Hive 可以通過本地模式在單台機器上(或某些時候在單個進程中)處理所有的任務。對於小數據集,執行時間可以明顯被縮短。
用戶可以按照如下這個例子中所演示的方式,在執行過程中臨時啟用本地模式:
用戶可以通過設置屬性hive.exec.mode.local.auto的值為true,來讓Hive在適當的時候自動啟動這個優化。通常用戶可以將這個配置寫在8HOME/.hiverc文件中。如果希望對所有的用戶都使用這個配置,那么可以將這個配置項增加到SHIVE_ HOME/conf/hive-site.xml文件中:
4)並行執行:
Hive會將-一個查詢轉化成一個或者多個階段。這樣的階段可以是MapReduce階段、抽樣階段、合並階段、limit階段,或者Hive執行過程中可能需要的其他階段。默認情況下,Hive一次只會執行一個階段。不過,某個特定的job可能包含眾多的階段,而這些階段可能並非完全互相依賴的,也就是說有些階段是可以並行執行的,這樣可能使得整個job的執行時間縮短。不過,如果有更多的階段可以並行執行,那么job可能就越快完成。
通過設置參數hive.exec.parallel值為true,就可以開啟並發執行。不過,在共享集群中,需要注意下,如果job中並行執行的階段增多,那么集群利用率就會增加:
5)嚴格模式
Hive提供了一個嚴格模式,可以防止用戶執行那些可能產生意想不到的不好的影響的查詢。
通過設置屬性hive.mapred.mode值為strict可以禁止3種類型的查詢。
其一,對於分區表,除非WHEHRE語句中含有分區字段過濾條件來限制數據范圍,否則不允許執行。換句話說,就是用戶不允許掃描所有分區。進行這個限制的原因是,通常分區表都擁有非常大的數據集,而且數據增加迅速。沒有進行分區限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表:
如下這個語句在WHERE語句中增加了一個分區過濾條件(也就是限制了表分區):
其二,對於使用了ORDER BY語句的查詢,要求必須使用LIMIT語句。因為ORDER BY為了執行排序過程會將所有的結果數據分發到同一個reducer中進行處理,強制要求用戶增加這個LIMIT語句可以防止reducer額外執行很長一段時間:
只需要增加LIMIT語句就可以解決這個問題:
其三,也就是最后一種情況,就是限制笛卡爾積的查詢。對關系型數據庫非常了解的用戶可能期望在執行JOIN查詢的時候不使用ON語句而是使用WHERE語句,這樣關系型數據庫的執行優化器就可以高效地將WHERE語句轉化成那個ON語句。不幸的是,Hive並不會執行這種優化,因此,如果表足夠大,那么這個查詢就會出現不可控的情況:
下面這個才是個正確的使用JOIN和ON語句的查詢:
6)調整mapper和reducer個數
Hive通過將查詢划分成-一個或者多個MapReduce任務達到並行的目的。每個任務都可能具有多個mapper和reducer 任務,其中至少有一些是可以並行執行的。確定最佳的mapper個數和reducer個數取決於多個變量,例如輸人的數據量大小以及對這些數據執行的操作類型等。
保持平衡性是有必要的。如果有太多的mapper或reducer任務,就會導致啟動階段、調度和運行job過程中產生過多的開銷;而如果設置的數量太少,那么就可能沒有充分利用好集群內在的並行性。
當執行的Hive查詢具有reduce過程時,CLI 控制台會打印出調優后的reducer個數。下面我們來看一個包含有GROUP BY語句的例子,因為這種查詢總是需要reduce過程的。與此相反,很多其他查詢會轉換成只需要map階段的任務:
Hive是按照輸人的數據量大小來確定reducer個數的。我們可以通過dfs - count命令來計算輸人量大小,這個命令和Linux中的du -s命令類似;其可以計算指定目錄下所有數據的總大小:
屬性hive.exec.reducers.bytes.per.reducer 的默認值是1GB。 如果將這個屬性值調整為750MB的話,那么下面這個任務Hive就會使用4個reducer:
默認值通常情況下是比較合適的。不過,有些情況下查詢的map階段會產生比實際輸入數據量要多得多的數據。如果map階段產生的數據量非常多,那么根據輸人的數據量大小來確定的reducer個數就顯得有些少了。同樣地,map階段也可能會過濾掉輸入數據集中的很大一部分的數據而這時可能需要少量的reducer就滿足計算了。
一個快速的進行驗證的方式就是將reducer 個數設置為固定的值,而無需Hive來計算得到這個值。如果用戶還記得的話,Hive 的默認reducer個數應該是3。可以通過設置屬性mapred.reduce.tasks 的值為不同的值來確定是使用較多還是較少的reducer來縮短執行時間。需要記住,受外部因素影響,像這樣的標桿值十分復雜,例如其他用戶並發執行job的情況。Hadoop需要消耗好幾秒時間來啟動和調度map和reduce任務(task)。 在進行性能測試的時候,要考慮到這些影響因子,特別是job比較小的時候。
當在共享集群上處理大任務時,為了控制資源利用情況,屬性hive.exec.reducers.max顯得非常重要。一個Hadoop集群可以提供的map和reduce 資源個數(也稱為“插槽”),是固定的。某個大job可能就會消耗完所有的插槽,從而導致其他job無法執行。通過設置屬性hive.exec.reducers.max可以阻止某個查詢消耗太多的reducer資源。有必要將這個屬性配置到$HIVE_ HOME/confhive-site.xml 文件中。對這個屬性值大小的一個建議的計算公式如下:
(集群總Reduce槽位個數*1.5) / (執行中的查詢的平均個數)
1.5倍數是一個經驗系數,用於防止未充分利用集群的情況。
7)JVM重用
JVM重用是Hadoop調優參數的內容,其對Hive的性能具有非常大的影響,特別是對於很難避免小文件的場景或task特別多的場景,這類場景大多數執行時間都很短。Hadoop的默認配置通常是使用派生JVM來執行map和reduce任務的。這時JVM的啟動過程可能會造成相當大的開銷,尤其是執行的job包含有成百上千個task任務的情況。JVM重用可以使得JVM實例在同一一個job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件(位於 $ HADOOP_ HOME/conf 目錄下)中進行設置:
這個功能的一一個缺點是,開啟JVM重用將會- -直占用使用到的task插槽,以便進行重用,直到任務完成后才能釋放。如果某個“不平衡的”的job中有某幾個reduce task執行的時間要比其他reduce task 消耗的時間多得多的話,那么保留的插槽就會一直空閑着卻無法被其他的job使用,直到所有的task都結束了才會釋放。
8)索引
索引可以用來加快含有GROUP BY語句的查詢的計算速度。Hive從v0.8.0版本后增加了一個bitmap索引實現。Bitmap索引一般在指定的列排重后的值比較小時進行使用。例:
9)動態分區調整
動態分區INSERT語句可以通過簡單的SELECT語句向分區表中創建很多新的分區。這是-一個非常強大的功能,不過如果分區的個數非常得多,那么就會在系統中產生大量的輸出控制流。對於Hadoop來說,這種情況並不是常見的使用場景,因此,其通常會一次創建很多的文件,然后會向這些文件中寫人大量的數據。
跳出這些框框, Hive可以通過配置限制動態分區插入允許創建的分區數在1000個左右。雖然太多的分區對於表來說並不好,不過,通常還是將這個值設置的更大以便這些查詢執行。
首先,通常在hive- site.xml配置文件中設置動態分區模式為嚴格模式(也就是屬性值為strict), 開啟嚴格模式的時候,必須保證至少有一個分區是靜態的。
然后,可以增加一些相關的屬性信息,例如通過如下屬性來限制查詢可以創建的最大動態分區個數:
還有一個配置是來控制DataNode上一次可以打開的文件的個數。這個參數必須設置在DataNode的$HADOOP_ HOME/conf/hdfs-site.xml 配置文件中。
在Hadoop v0.20.2版本中,這個屬性的默認值是256,太小了。這個值會影響到最大的線程數和資源數,因此,也並不推薦將這個屬性值設置為-一個極大值。同時需要注意的是,在Hadoop v0.20.2版本中,更改這個屬性值需要重啟DataNode才能夠生效:
10)推測執行
推測執行是Hadoop中的-一個功能,其可以觸發執行一-些重復的任務 (task)。 盡管這樣會因對重復的數據進行計算而導致消耗更多的計算資源,不過這個功能的目標是通過加快獲取單個task的結果以及進行偵測將執行慢的TaskTracker加人到黑名單的方式來提高整體的任務執行效率。
Hadoop的推測執行功能由 $HADOOP_ HOME/conf/mapred-site.xml 文件中的如下2個配置項控制着:
不過,Hive 本身也提供了配置項來控制reduce-side的推測執行:
關於調優這些推測執行變量,還很難給一個具體的建議。如果用戶對於運行時的偏差非常敏感的話,那么可以將這些功能關閉掉。如果用戶因為輸入數據量很大而需要執行長時間的map或者reduce task的話,那么啟動推測執行造成的浪費是非常巨大的。
11)單個MapReduce中多個GROUP BY
另一個特別的優化試圖將查詢中的多個GROUPBY操作組裝到單個MapReduce任務中。如果想啟動這個優化,那么需要一-組常用的GROUP BY鍵:
12)虛擬列
Hive提供了2種虛擬列:一 種用於將要進行划分的輸人文件名,另-種用於文件中的塊內偏移量。當Hive產生了非預期的或null的返回結果時,可以通過這些虛擬列診斷查詢。通過查詢這些”字段”,用戶可以查看到哪個文件甚至哪行數據導致出現問題:
第3種虛擬列提供了文件的行偏移量。這個需要通過如下參數顯式地啟用:
這樣設置后就可以在類似於如下的查詢中使用了
參考:https://blog.csdn.net/wxfghy/article/details/81361400 Hive優化: 1.通用設置 hive.optimize.cp=true:列裁剪 hive.optimize.prunner:分區裁剪 hive.limit.optimize.enable=true:優化LIMIT n語句 hive.limit.row.max.size=1000000: hive.limit.optimize.limit.file=10:最大文件數 2.本地模式(小任務) 1)job的輸入數據大小必須小於參數:hive.exec.mode.local.auto.inputbytes.max(默認128MB) 2)job的map數必須小於參數:hive.exec.mode.local.auto.tasks.max(默認4) 3)job的reduce數必須為0或者1 hive.exec.mode.local.auto.inputbytes.max=134217728 hive.exec.mode.local.auto.tasks.max=4 hive.exec.mode.local.auto=true hive.mapred.local.mem:本地模式啟動的JVM內存大小 3.並發執行 hive.exec.parallel=true ,默認為false hive.exec.parallel.thread.number=8 4.Strict Mode: hive.mapred.mode=true,嚴格模式不允許執行以下查詢: 分區表上沒有指定了分區 沒有limit限制的order by語句 笛卡爾積:JOIN時沒有ON語句 5.動態分區 hive.exec.dynamic.partition.mode=strict:該模式下必須指定一個靜態分區 hive.exec.max.dynamic.partitions=1000 hive.exec.max.dynamic.partitions.pernode=100:在每一個mapper/reducer節點允許創建的最大分區數 DATANODE:dfs.datanode.max.xceivers=8192:允許DATANODE打開多少個文件 6.推測執行 mapred.map.tasks.speculative.execution=true mapred.reduce.tasks.speculative.execution=true hive.mapred.reduce.tasks.speculative.execution=true; 7.多個group by合並 hive.multigroupby.singlemar=true:當多個GROUP BY語句有相同的分組列,則會優化為一個MR任務 8.虛擬列 hive.exec.rowoffset:是否提供虛擬列 9.分組 1)兩個聚集函數不能有不同的DISTINCT列,以下表達式是錯誤的: INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(DISTINCT pv_users.ip) FROM pv_users GROUP BY pv_users.gender; 2)SELECT語句中只能有GROUP BY的列或者聚集函數。 10.Combiner聚合 hive.map.aggr=true;在map中會做部分聚集操作,效率更高但需要更多的內存。 hive.groupby.mapaggr.checkinterval:在Map端進行聚合操作的條目數目 11.數據傾斜 1)hive.groupby.skewindata=true:數據傾斜時負載均衡,當選項設定為true,生成的查詢計划會有兩個MRJob。 2)第一個MRJob 中,Map的輸出結果集合會隨機分布到Reduce中,每個Reduce做部分聚合操作,並輸出結果,這樣處理的結果是相同的GroupBy Key 有可能被分發到不同的Reduce中,從而達到負載均衡的目的; 3)第二個MRJob再根據預處理的數據結果按照GroupBy Key分布到Reduce中(這個過程可以保證相同的GroupBy Key被分布到同一個Reduce中),最后完成最終的聚合操作。 12.排序 ORDER BY colName ASC/DESC hive.mapred.mode=strict時需要跟limit子句 hive.mapred.mode=nonstrict時使用單個reduce完成排序 SORT BY colName ASC/DESC :每個reduce內排序 DISTRIBUTE BY(子查詢情況下使用 ):控制特定行應該到哪個reducer,並不保證reduce內數據的順序 CLUSTER BY :當SORT BY 、DISTRIBUTE BY使用相同的列時。 13.合並小文件 hive.merg.mapfiles=true:合並map輸出 hive.merge.mapredfiles=false:合並reduce輸出 hive.merge.size.per.task=256*1000*1000:合並文件的大小 hive.mergejob.maponly=true:如果支持CombineHiveInputFormat則生成只有Map的任務執行merge hive.merge.smallfiles.avgsize=16000000:文件的平均大小小於該值時,會啟動一個MR任務執行merge。 14.自定義map/reduce數目 1)減少map數目: set mapred.max.split.size set mapred.min.split.size set mapred.min.split.size.per.node set mapred.min.split.size.per.rack set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat 2)增加map數目: 1>當input的文件都很大,任務邏輯復雜,map執行非常慢的時候,可以考慮增加Map數,來使得每個map處理的數據量減少,從而提高任務的執行效率。 2>假設有這樣一個任務: select data_desc, count(1), count(distinct id),sum(case when …),sum(case when ...),sum(…) from a group by data_desc 3>如果表a只有一個文件,大小為120M,但包含幾千萬的記錄,如果用1個map去完成這個任務,肯定是比較耗時的,這種情況下,我們要考慮將這一個文件合理的拆分成多個,這樣就可以用多個map任務去完成。 set mapred.reduce.tasks=10; create table a_1 as select * from a distribute by rand(123); 4>這樣會將a表的記錄,隨機的分散到包含10個文件的a_1表中,再用a_1代替上面sql中的a表,則會用10個map任務去完成。每個map任務處理大於12M(幾百萬記錄)的數據,效率肯定會好很多。 3)reduce數目設置: 1>參數1:hive.exec.reducers.bytes.per.reducer=1G:每個reduce任務處理的數據量 2>參數2:hive.exec.reducers.max=999(0.95*TaskTracker數):每個任務最大的reduce數目 3>reducer數=min(參數2,總輸入數據量/參數1) 4>set mapred.reduce.tasks:每個任務默認的reduce數目。典型為0.99*reduce槽數,hive將其設置為-1,自動確定reduce數目。 15.使用索引: hive.optimize.index.filter:自動使用索引 hive.optimize.index.groupby:使用聚合索引優化GROUP BY操作
- 1
9.簡要描述數據庫中的 null,說出null在hive底層如何存儲,並解釋 select a. * from t1 a left outer join t2 b on a.id=b.id where b.id is null; 語句的含義。
1)null與任何值運算的結果都是null, 可以使用is null、is not null函數指定在其值為null情況下的取值。
2)null在hive底層默認是用’\N’來存儲的,可以通過alter table test SET SERDEPROPERTIES(‘serialization.null.format’ = ‘a’);來修改。
3)查詢出t1表中與t2表中id相等的所有信息。
10.寫出hive中split、coalesce及collect_list函數的用法(可舉例)。
split將字符串轉化為數組。
split(‘a,b,c,d’ , ‘,’) ==> [“a”,“b”,“c”,“d”]
COALESCE(T v1, T v2, …) 返回參數中的第一個非空值;如果所有值都為 NULL,那么返回NULL。
collect_list列出該字段所有的值,不去重 select collect_list(id) from table;
11.寫出將 text.txt 文件放入 hive 中 test 表‘2016-10-10’ 分區的語句,test 的分區字段是 l_date。
LOAD DATA LOCAL INPATH '/your/path/test.txt' OVERWRITE INTO TABLE test PARTITION (l_date='2016-10-10')
- 1
12.Multi-group by 是hive的一個非常好的特性,請舉例說明?
multi group by 可以將查詢中的多個group by操作組裝到一個MapReduce任務中,起到優化作用。
例子:
select Provice,city,county,count(rainfall) from area where data="2018-09-02" group by provice,city,count select Provice,count(rainfall) from area where data="2018-09-02" group by provice
- 1
- 2
- 3
使用multi group by:
from area insert overwrite table temp1 select Provice,city,county,count(rainfall) from area where data="2018-09-02" group by provice,city,count insert overwrite table temp2 select Provice,count(rainfall) from area where data="2018-09-02" group by provice
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
使用multi group by 之前必須配置參數:
<property> <name>hive.multigroupby.singlemr</name> <value>true</value> </property>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
13.請談一下hive的特點是什么?hive和RDBMS有什么異同?
hive由Facebook開源用於解決海量結構化日志的數據統計,是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張數據庫表,並提供完整的sql查詢功能,可以將sql語句轉換為MapReduce任務進行運行。其優點是學習成本低,可以通過類SQL語句快速實現簡單的MapReduce統計,不必開發專門的MapReduce應用,十分適合數據倉庫的統計分析。
1)hive存儲的數據量比較大,適合海量數據,適合存儲軌跡類歷史數據,適合用來做離線分析、數據挖掘運算,事務性較差,實時性較差。rdbms一般數據量相對來說不會太大,適合事務性計算,實時性較好,更加接近上層業務。
2)hive的計算引擎是hadoop的mapreduce,存儲是hadoop的hdfs文件系統。rdbms的引擎由數據庫自己設計實現例如mysql的innoDB,存儲用的是數據庫服務器本地的文件系統。
3)hive由於基於hadoop所以存儲和計算的擴展能力都很好,rdbms在這方面比較弱,比如orcale的分表和擴容就很頭疼。
4)hive表格沒有主鍵、沒有索引、不支持對具體某一行的操作,適合對批量數據的操作,不支持對數據的update操作,更新的話一般是先刪除表然后重新落數據rdbms事務性強,有主鍵、索引,支持對具體某一行的增刪改查等操作。
5)hive的SQL為HQL,與標准的RDBMS的SQL存在有不少的區別,相對來說功能有限rdbms的SQL為標准SQL,功能較為強大。
6)Hive在加載數據時候和rdbms關系數據庫不同,hive在加載數據時候不會對數據進行檢查,也不會更改被加載的數據文件,而檢查數據格式的操作是在查詢操作時候執行,這種模式叫“讀時模式”。在實際應用中,寫時模式在加載數據時候會對列進行索引,對數據進行壓縮,因此加載數據的速度很慢,但是當數據加載好了,我們去查詢數據的時候,速度很快。但是當我們的數據是非結構化,存儲模式也是未知時候,關系數據操作這種場景就麻煩多了,這時候hive就會發揮它的優勢。
rdbms里,表的加載模式是在數據加載時候強制確定的(表的加載模式是指數據庫存儲數據的文件格式),如果加載數據時候發現加載的數據不符合模式,關系數據庫則會拒絕加載數據,這個就叫“寫時模式”,寫時模式會在數據加載時候對數據模式進行檢查校驗的操作。
總結:Hive並非為聯機事務處理而設計,Hive並不提供實時的查詢和基於行級的數據更新操作。Hive是建立在Hadoop之上的數據倉庫軟件工具,它提供了一系列的工具,幫助用戶對大規模的數據進行提取、轉換和加載,即通常所稱的ETL(Extraction,Transformation,and Loading)操作。Hive可以直接訪問存儲在HDFS或者其他存儲系統(如Hbase)中的數據,然后將這些數據組織成表的形式,在其上執行ETL操作。 HIVE是數據倉庫適合存儲歷史的海量的數據,適合做批量和海量復雜運算,事務性差,運算時間長。RDBMS是數據庫,存儲數據量偏小一些,事務性強,適合做OLTP和OLAP業務,運算時間短。Hive的最佳使用場合是大數據集的批處理作業,例如,網絡日志分析。
● 1)查詢語言。 由於SQL被廣泛的應用在數據倉庫中,因此,專門針對Hive的特性設計了類SQL的查詢語言HQL。熟悉SQL開發的開發者可以很方便的使用Hive進行開發。 ● 2)數據存儲位置。 Hive是建立在Hadoop之上的,所有Hive的數據都是存儲在HDFS中的。而數據庫則可以將數據保存在塊設備或者本地文件系統中。 ● 3)數據更新。 由於Hive是針對數據倉庫應用設計的,而數據倉庫的內容是讀多寫少的。因此,Hive中不建議對數據的改寫,所有的數據都是在加載的時候確定好的。而數據庫中的數據通常是需要經常進行修改的,因此可以使用INSERT NT0.... VALUES添加數據,使用UPDATE...SET修改數據。 ● 4)索引。 Hive在加載數據的過程中不會對數據進行任何處理,甚至不會對數據進行掃描,因此也沒有對數據中的某些Key建立索引。Hive 要訪問數據中滿足條件的特定值時,需要暴力掃描整個數據,因此訪問延遲較高。由於MapReduce的引入,Hive 可以並行訪問數據,因此即使沒有索引,對於大數據量的訪問,Hive 仍然可以體現出優勢。數據庫中,通常會針對一個或者幾個列建立索引,因此對於少量的特定條件的數據的訪問,數據庫可以有很高的效率,較低的延遲。由於數據的訪問延遲較高,決定了Hive 不適合在線數據查詢。 ● 5)執行。 Hive中大多數查詢的執行是通過Hadoop提供的MapReduce來實現的。而數據庫通常有自己的執行引擎。 ● 6)執行延遲。 Hive在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高。另外一個導致Hive執行延遲高的因素是MapReduce框架。由於MapReduce 本身具有較高的延遲,因此在利用MapReduce執行Hive查詢時,也會有較高的延遲。相對的,數據庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過數據庫的處理能力的時候,Hive 的並行計算顯然能體現出優勢。 ● 7)可擴展性。 由於Hive是建立在Hadoop之上的,因此Hive的可擴展性是和Hadoop的可擴展性是一致的(世界上最大的Hadoop集群在Yahoo!, 2009 年的規模在4000台節點左右)。而數據庫由於ACID語義的嚴格限制,擴展行非常有限。目前最先進的並行數據庫Oracle在理論上的擴展能力也只有100台左右。 ● 8)數據規模。 由於Hive建立在集群上並可以利用MapReduce進行並行計算,因此可以支持很大規模的數據;對應的,數據庫可以支持的數據規模較小。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
14.hive架構
1.用戶接口: Client
CLI (hive shell)、JDBC/ODBC(java訪問hive)、WEBUI (瀏覽器訪問hive)。
2.元數據: Metastore。
元數據包括:表名、表所屬的數據庫(默認是default) 、表的擁有者、列/分區字段、表的類型(是否是外部表)、表的數據所在目錄等;
默認存儲在自帶的derby數據庫中,推薦使用MySQL存儲Metastore
3.Hadoop。
使用HDFS進行存儲,使用MapReduce進行計算。。
4.驅動器: Drivers
(1)解析器(SQL Parser):將SQL字符串轉換成抽象語法樹AST,這一步一般都用第三方工具庫完成,比如antlr;對AST進行語法分析,比如表是否存在、字段是否存在、SQL語義是否有誤。
(2)編譯器(Physical Plan):將AST編譯生成邏輯執行計划。。
(3)優化器(Query Optimizer):對邏輯執行計划進行優化。
(4)執行器(Execution):把邏輯執行計划轉換成可以運行的物理計划。對於Hive來說,就是MR/Spark。
參考:https://blog.csdn.net/qq_35036995/article/details/80298403
https://blog.csdn.net/u011317245/article/details/53977771