hive中嚴格模式和非嚴格模式的區別
hive嚴格模式
hive提供了一個嚴格模式,可以防止用戶執行那些可能產生意想不到的不好的效果的查詢。即某些查詢在嚴格
模式下無法執行。通過設置hive.mapred.mode的值為strict,可以禁止3中類型的查詢。
1)帶有分區的表的查詢
如果在一個分區表執行hive,除非where語句中包含分區字段過濾條件來顯示數據范圍,否則不允許執行。換句話說,
就是用戶不允許掃描所有的分區。進行這個限制的原因是,通常分區表都擁有非常大的數據集,而且數據增加迅速。
如果沒有進行分區限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表:
hive> SELECT DISTINCT(planner_id) FROM fracture_ins WHERE planner_id=5;
FAILED: Error in semantic analysis: No Partition Predicate Found for Alias "fracture_ins" Table "fracture_ins
如下這個語句在where語句中增加了一個分區過濾條件(也就是限制了表分區):
hive> SELECT DISTINCT(planner_id) FROM fracture_ins
> WHERE planner_id=5 AND hit_date=20120101;
... normal results ...
2)帶有orderby的查詢
對於使用了orderby的查詢,要求必須有limit語句。因為orderby為了執行排序過程會講所有的結果分發到同一個reducer中
進行處理,強烈要求用戶增加這個limit語句可以防止reducer額外執行很長一段時間:
hive> SELECT * FROM fracture_ins WHERE hit_date>2012 ORDER BY planner_id;
FAILED: Error in semantic analysis: line 1:56 In strict mode,
limit must be specified if ORDER BY is present planner_id
只需要增加limit語句就可以解決這個問題:
hive> SELECT * FROM fracture_ins WHERE hit_date>2012 ORDER BY planner_id
> LIMIT 100000;
... normal results ...
3)限制笛卡爾積的查詢
對關系型數據庫非常了解的用戶可能期望在執行join查詢的時候不使用on語句而是使用where語句,這樣關系數據庫的執行
優化器就可以高效的將where語句轉換成那個on語句。不幸的是,hive不會執行這種優化,因此,如果表足夠大,那么這個查詢就會
出現不可控的情況:
hive> SELECT * FROM fracture_act JOIN fracture_ads
> WHERE fracture_act.planner_id = fracture_ads.planner_id;
FAILED: Error in semantic analysis: In strict mode, cartesian product
is not allowed. If you really want to perform the operation,
+set hive.mapred.mode=nonstrict+
下面這個才是正確的使用join和on語句的查詢:
hive> SELECT * FROM fracture_act JOIN fracture_ads
> ON (fracture_act.planner_id = fracture_ads.planner_id);
... normal results ...
歸納:
1.對分區表進行查詢,必須使用where+分區字段來限制范圍。
2.使用orderby查詢的時候,必須加上limit限制,因為執行order by的時候,已經將所有的數據放到了一個reduce中了。
3.限制笛卡爾積的查詢,因為在關系型數據庫中,可以使用where充當on,但是在hive數據倉庫中,必須使用on。
Hive 非嚴格模式
hive配置中對hive.exec.dynamic.partition.mode的說法如下:
在嚴格模式下,用戶必須指定至少一個靜態分區
以防用戶意外覆蓋所有分區。
在非嚴格模式下,所有分區都允許是動態的。
事實上,我們很多時候都需要設置為非嚴格模式
設置成非嚴格模式的兩種方式:
1.每次hive會話的時候設置如下參數:
set hive.exec.dynamic.partition.mode=nonstrict;
不加會報錯:Error: org.apache.spark.SparkException: Dynamic partition strict mode requires at least one static partition column. To turn this off set hive.exec.dynamic.partition.mode=nonstrict (state=,code=0)
提示夠明顯吧?
2.在配置中修改參數,使之成為永久的,就不需要每次使用都去設置了,累人
修改conf中的hive-default.xml.template:
cp hive-default.xml.template hive-default.xml
vi hive-default.xml
找到hive.exec.dynamic.partition.mode 將值:strict改為nonstrict,重啟hive使之生效即可
————————————————
Hive JOIN
寫join查詢時,需要注意幾個關鍵點:
1)只支持等值join,因為非等值連接非常難轉化為MapReduce任務
示例:select a.* from a join b on a.id = b.id是正確的,然而:select a.* from a join b on a.id>b.id是錯誤的。
2)可以join多個表,如果join中多個表的join的列是同一個,則join會被轉化為單個MapReduce任務
示例:select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col1被轉化為單個MapReduce任務,因為join中只使用了b.col1作為join列。
但是如下寫法會被轉化為2個MapReduce任務。因為 b.col1用於第一次join條件,而 b.col2用於第二次 join
select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col2;
3)join時,轉換為MapReduce任務的邏輯
reduce會緩存join序列中除了最后一個表的所有表的記錄(具體看啟動了幾個map/reduce任務),再通過最后一個表將結果序列化到文件系統。這一實現有助於在reduce端減少內存的使用量。實踐中,應該把最大的那個表寫在最后(否則會因為緩存浪費大量內存)。示例:a.單個map/reduce任務select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col1中所有表都使用同一個join列。reduce端會緩存a表和b表的記錄,然后每次取得一個c表的記錄就計算一次join結果;b.多個map/reduce任務
select a.*, b.*, c.* from a join b on (a.col= b.col1) join c on (c.col= b.col2)。第一次緩存a表,用b表序列化;第二次緩存第一次MapReduce任務的結果,然后用c表序列化。
4)left semi join
經常用來替換 in和exists。
如,select * from a left semi join b on a.id = b.id; 相當於select * from a where a.id in (select b.id from b);但這種方式在hive中效率極低。