5、HIVE DML操作、load數據、update、Delete、Merge、where語句、基於分區的查詢、HAVING子句、LIMIT子句、Group By語法、Hive 的Join操作等

目錄:
4.2.1 Load文件數據到表中
4.2.2查詢的數據插入到表中
4.2.3將Hive查詢的結果存到本地Linux的文件系統目錄中
4.2.4通過SQL語句的方式插入數據
4.2.5 UPDATE
4.2.6 Delete
4.2.7 Merge
4.3.2WHERE子句
4.3.4基於分區的查詢
4.3.5 HAVING子句
4.3.6 LIMIT子句
4.3.7 Group By語法
4.3.7.1簡單案例
4.3.8 Select 語句和group by子句
4.3.8.1 Multi-Group-By Inserts
4.3.8.2 Map-side Aggregation for Group By
4.3.8.3 Group By約束條件
4.4 Order, Sort, Cluster, and Distribute By
4.4.1 Order By的語法
4.4.2 Sort By的語法
4.4.3 Order By和Sort By之間的異同
4.4.4 Cluster By和Distribute By的語法
4.5 Hive 的Join操作
4.5.1 Hive的join語法
4.5.2MapJoin的限制條件
4.6Union Syntax
4.6.1 FROM子句中的UNION
4.6.2 Unions in DDL and Insert Statements
4.7 SubQueries
4.7.1 在FROM子句中的Subqueries
4.7.2 Subqueries in the WHERE Clause
4.8 Import/Export
4.8.1 Export/Import語法
4.8.2 Replication語法
4.8.3 export,import

  1. 簡單導出和導出
  2. 在import時重命名錶
  3. 導出分區並導入
  4. 導出表並且導入到分區表分區
  5. 指定導入位置
  6. 導入作爲一個外部表

4.2.1 Load文件數據到表中

加載數據到表中

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

案例:

CREATE TABLE IF NOT EXISTS employee(eid int,name String,destination String)
partitioned by(salary String)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

hive> desc employee;
OK
eid                 	int                 	                    
name                	string              	                    
destination         	string              	                    
salary              	string              	                    
	 	 
# Partition Information	 	 
# col_name            	data_type           	comment             
	 	 
salary              	string              	                    
Time taken: 0.607 seconds, Fetched: 9 row(s)
hive>

創建/root/test/sample.txt,內容如下:
1201 pal 45000 Technical manager
1202 Manisha 45000 Proof reader

將上面的數據導入到employee表中:
hive> LOAD DATA LOCAL INPATH '/root/test/sample.txt' INTO TABLE employee PARTITION(salary = '45000');
Loading data to table demo_db.employee partition (salary=45000)
OK
Time taken: 1.392 seconds
hive>

上面的具體含義是將數據添加到45000這個分區中。
添加之後,在hdfs中的效果如下:
在這裏插入圖片描述

再添加salary=40000的分區,並指定分區數據的位置:

hive> ALTER TABLE employee ADD PARTITION (salary = '40000') location '/40000/part40000';
OK
Time taken: 0.203 seconds
hive> show partitions employee;
OK
salary=40000
salary=45000
Time taken: 0.206 seconds, Fetched: 2 row(s)
hive>

將以下數據添加到hdfs中:
在這裏插入圖片描述
在這裏插入圖片描述
將數據添加到salary=40000的分區中:
在這裏插入圖片描述

4.2.2查詢的數據插入到表中

標準語法:

INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;

4.2.3將Hive查詢的結果存到本地Linux的文件系統目錄中

語法:

Standard syntax:
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
  [ROW FORMAT row_format] [STORED AS file_format] (Note: Only available starting with Hive 0.11.0)
  SELECT ... FROM ...
 
Hive extension (multiple inserts):
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...

row_format
  : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
        [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
        [NULL DEFINED AS char] (Note: Only available starting with Hive 0.13)

案例:
hive> INSERT OVERWRITE LOCAL DIRECTORY '/employee'
    > ROW FORMAT DELIMITED
    > FIELDS TERMINATED BY '\t'
    > LINES TERMINATED BY '\n'
    > STORED AS TEXTFILE
> select * from employee;

在這裏插入圖片描述
進入本地Linux查看效果:
在這裏插入圖片描述

4.2.4通過SQL語句的方式插入數據

語法:

INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...]

案例:

CREATE TABLE students (name VARCHAR(64), age INT, gpa DECIMAL(3, 2))
  CLUSTERED BY (age) INTO 2 BUCKETS STORED AS ORC;
 
INSERT INTO TABLE students
  VALUES ('fred flintstone', 35, 1.28), ('barney rubble', 32, 2.32);
 
 
CREATE TABLE pageviews (userid VARCHAR(64), link STRING, came_from STRING)
  PARTITIONED BY (datestamp STRING) CLUSTERED BY (userid) INTO 256 BUCKETS STORED AS ORC;
 
INSERT INTO TABLE pageviews PARTITION (datestamp = '2014-09-23')
  VALUES ('jsmith', 'mail.com', 'sports.com'), ('jdoe', 'mail.com', null);
 
INSERT INTO TABLE pageviews PARTITION (datestamp)
  VALUES ('tjohnson', 'sports.com', 'finance.com', '2014-09-23'), ('tlee', 'finance.com', null, '2014-09-21');
  
INSERT INTO TABLE pageviews
  VALUES ('tjohnson', 'sports.com', 'finance.com', '2014-09-23'), ('tlee', 'finance.com', null, '2014-09-21');

4.2.5 UPDATE

若想讓Hive庫能夠支持UPDATE,需要讓它能夠支持 Hive Transactions (https://cwiki.apache.org/confluence/display/Hive/Hive+Transactions)

語法是:

UPDATE tablename SET column = value [, column = value ...] [WHERE expression]

4.2.6 Delete

若想讓Hive庫能夠支持DELETE,需要讓它能夠支持 Hive Transactions (https://cwiki.apache.org/confluence/display/Hive/Hive+Transactions)

語法是:

DELETE FROM tablename [WHERE expression]

4.2.7 Merge

語法:

MERGE INTO <target table> AS T USING <source expression/table> AS S
ON <boolean expression1>
WHEN MATCHED [AND <boolean expression2>] THEN UPDATE SET <set clause list>
WHEN MATCHED [AND <boolean expression3>] THEN DELETE
WHEN NOT MATCHED [AND <boolean expression4>] THEN INSERT VALUES<value list>

4.3 數據檢索—Queries

4.3.1Select語法

SELECT [ALL | DISTINCT] select_expr, select_expr, ...
  FROM table_reference
  [WHERE where_condition]
  [GROUP BY col_list]
  [ORDER BY col_list]
  [CLUSTER BY col_list
    | [DISTRIBUTE BY col_list] [SORT BY col_list]
  ]
 [LIMIT [offset,] rows]
1Select語句可以作爲union查詢和子查詢等的一部分。
2、table_reference可以是一個普通的表,視圖,一個join構造或者一個子查詢。
3、表名和列名是大小寫不敏感的。
        A:在Hive 0.12及其早期版本中,在表明和列名中只有字母和下劃線才被允許。
        B:在Hive 0.13及其後期版本中,列名中可以包含任何的Unicode字符。

案例:
從t1中獲取所有的列和行數

SELECT * FROM t1 

獲取當前在使用的數據庫:

SELECT current_database()

4.3.2WHERE子句

案例:

SELECT * FROM sales WHERE amount > 10 AND region = "US"

4.3.3ALL和DISTINCT子句

ALL和DISTINCT選項指定是否返回重複的行。如果這兩個都沒有指定,默認是ALL(所有的數據都將會被返回),DISTINCT指定之後,將會移除所有重複行。從Hive 1.1.0之後,Hive開始支持SELECT DISTINCT *查詢。

hive> SELECT col1, col2 FROM t1
    1 3
    1 3
    1 4
    2 5
hive> SELECT DISTINCT col1, col2 FROM t1
    1 3
    1 4
    2 5
hive> SELECT DISTINCT col1 FROM t1
    1
    2

所有的ALL和DISTINCT也可以在UNION子句中使用。

4.3.4基於分區的查詢

一般而言,一個SELECT查詢將掃描全表(而不是部分數據)。如果一個表是使用PARTITIONED BY創建的,在查詢的時候,可以只掃描分區對應的一部分數據。
假設有一個page_views表,這個表是按照date進行分區的,可以通過下面的語句檢索出數據行在2008-03-01和2008-03-31之間的數據行。

SELECT page_views.*
FROM page_views
WHERE page_views.date >= '2008-03-01' AND page_views.date <= '2008-03-31'

如果表page_views和dim_users之間進行join操作,在ON子句裏面可以指定一些分區。

SELECT page_views.*
FROM page_views JOIN dim_users
  ON (page_views.user_id = dim_users.id AND page_views.date >= '2008-03-01' AND page_views.date <= '2008-03-31')

4.3.5 HAVING子句

HAVING子句的這種語法在0.7.0之後開始支持,當然使用子句也可以實現類似的功能。

SELECT col1 FROM t1 GROUP BY col1 HAVING SUM(col2) > 10

也可以使用子句實現:

SELECT col1 FROM (SELECT col1, SUM(col2) AS col2sum FROM t1 GROUP BY col1) t2 WHERE t2.col2sum > 10;

4.3.6 LIMIT子句

子句可以被用於約束SELECT子查詢的數據行數。
LIMIT接收1或2個數值參數,這兩個參數必須都是正整數。第一個參數指定獲取的第一行數據的偏移量。第二個參數表示一次性最多返回的數據行數。如果只指定了一個參數,它代表返回最大多少條數據,第一條數據的偏移位置是0。
下面的語句表示返回任意的5條數據。

SELECT * FROM customers LIMIT 5;

下面的查詢返回前5個數據

SELECT * FROM customers ORDER BY create_date LIMIT 5;

下面的查詢返回第3條到第7條的數據

SELECT * FROM customers ORDER BY create_date LIMIT 2,5;

4.3.7 Group By語法

語法:

Group By子句:GROUP BY groupByExpression (, groupByExpression)*

groupByExpression: expression

Group BY的完整語法:
SELECT expression (, expression)* FROM src groupByClause?

在groupByExpression中,列被指定位確切的名稱,不是根據位置數值。當配置一下參數的時候,可以通過指定位置的方式獲取數據。
1、Hive 0.11.0到2.1.x,設置 hive.groupby.orderby.position.alias 爲true (默認是false).
2、對於Hive 2.2.0及其以後版本,設置 hive.groupby.position.alias 爲true (默認是false).

4.3.7.1簡單案例

獲取表的數據行數

SELECT COUNT(*) FROM table2;

注意:對於不支持COUNT()的Hive版本,可以使用COUNT(1)代替COUNT()

爲了去重的方式獲取按照gender分組的用戶的數據行數,可以使用以下的命令:

INSERT OVERWRITE TABLE pv_gender_sum
SELECT pv_users.gender, count (DISTINCT pv_users.userid)
FROM pv_users
GROUP BY pv_users.gender;

可以同時使用多個聚合函數。聚合函數中的列名要相同。

INSERT OVERWRITE TABLE pv_gender_agg
SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(*), sum(DISTINCT pv_users.userid)
FROM pv_users
GROUP BY pv_users.gender;

注意,上面的COUNT()在有些Hive版本中可能不支持,需要使用COUNT(1)代替COUNT()。
下面的語法中,不支持一個語句中使用多個DISTINCT語句(這個語句中的列不相同),也就是說下面的SQL是錯的。

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;

4.3.8 Select 語句和group by子句

當使用group by子句的時候,select語句中的列只能是group by子句中包含的列,當然,你也可以在select語句中含有多個聚合函數(例如:count)。
讓我們舉一個簡單的例子:

CREATE TABLE t1(a INTEGER, b INTGER);

一個針對上面表的group查詢可以類似如下:

SELECT
   a,
   sum(b)
FROM
   t1
GROUP BY
   a;

上面的查詢起作用是因爲select子句中包含一個(group by key),並且有一個聚合函數(sum(b))
然而下面的查詢就不起作用。

SELECT
   a,
   b
FROM
   t1
GROUP BY
   a;

這是因爲在這個查詢子句中有一個額外的列(b),但是這個b不在group by子句中。並且它也不是一個聚合函數。這是因爲,表t1如下:

a    b
------
100  1
100  2
100  3

4.3.8.1 Multi-Group-By Inserts

將查詢到的數據插入到pv_gender_sum表中

INSERT OVERWRITE TABLE pv_gender_sum
  SELECT pv_users.gender, count(DISTINCT pv_users.userid)
  GROUP BY pv_users.gender

將查詢到的數據寫入到目錄文件中

INSERT OVERWRITE DIRECTORY '/user/facebook/tmp/pv_age_sum'
  SELECT pv_users.age, count(DISTINCT pv_users.userid)
  GROUP BY pv_users.age;

4.3.8.2 Map-side Aggregation for Group By

hive.map.aggr 控制我們怎樣進行聚合操作,它的默認值是false,如果將它設置成true,Hive將直接在map task中做第一級的聚合。

通常情況下,這種操作提供了更好的效率,但是如果想運行成功,需要更多的內存。

set hive.map.aggr=true;
SELECT COUNT(*) FROM table2;

要注意的是,有些hive版本不支持count(),需要使用count(1)代替count().

4.3.8.3 Group By約束條件

(1)、不能Group By非標量基元類型的列,如不能Group By text,image或bit類型的列。
(2)、帶有Group by子句的時候,Select指定的每一列都應該出現在Group By子句中,除非對這一列使用了聚合函數。聚合函數如:AVG、COUNT、MAX/MIN、SUM
(3)、不能Group By在表中不存在的列。
(4)、進行分組前可以使用Where子句消除不滿足條件的行。
(5)、使用Group By子句返回的組沒有特定的順序,可以使用Order By子句指定次序。

4.4 Order, Sort, Cluster, and Distribute By

4.4.1 Order By的語法

在Hive QL中的ORDER BY語法有點類似SQL語言中的ORDER BY語法。

SELECT 
expression (,’ expression)* 
FROM 
src 
ORDER BY 
colName (ASC | DESC)  (NULLS FIRST | NULLS LAST);

在”order by”子句中有一些限制,在嚴格模式下(即: hive.mapred.mode=strict)模式下,order by子句必須在”limit”子句的後面,如果你設置了hive.mapred.mode爲nonstrict,原因是爲了強制所有結果的總順序,必須有一個reduce去排序最終的結果。如果輸出結果太大,這單個reduce可能需要很長時間才能結束。

注意的是默認的排序是升序ascending(ASC).

在Hive 2.1.0及其以後版本中,支持了爲”order by”子句中的每列指定空值排序。對於ASC排序默認的排序是NULLS FIRST,然而,對於DESC排序默認的空值排序是NULLS LAST.

在Hive 3.0.0及更高版本中,沒有limit的order by子查詢和視圖將會被optimizer刪除。想要禁用它,得設置hive.remove.orderby.in.subquery 爲false。

4.4.2 Sort By的語法

SORT BY的語法類似SQL語言中的ORDER BY語法

SELECT
    Expression (,’  expression)*
FROM 
src
SORT BY
colName (ASC | DESC);

4.4.3 Order By和Sort By之間的異同

Hive支持SORT BY操作,在每個reducer中將sort數據。”order by”和”sort by”之間的不同之處是前者支持輸出的結果中所有的都是有序的,而後者只能支持在一個reducer中是有序的。如果有多個reduce,”sort by”可能返回的最終結果是部分有序的。
基本上,在每個reducer中的數據都將按照用戶指定的排序類型排序。例如下面的案例:

SELECT key, value FROM src SORT BY key ASC, value DESC

這個查詢有2個reducers,每個的輸出是:

0   5
0   3
3   6
9   1
0   4
0   3
1   1
2   5

4.4.4 Cluster By和Distribute By的語法

Cluster By和Distribute By主要用在Transform/Map-Reduce腳本中。如果需要分區和排序最終查詢的結果,有時候是很有用的。
Cluster By是Distribute By和Sort By的一個快捷的方式。

Hive在Distribute By中使用列的方式將在衆多的reducers中數據行均勻分佈。所有的擁有相同Distribute By獵德行都將被分配到相同的reducer中。然後,Distribute By不保證在distributed key上的clustering和sorting屬性。
例如:下面的5行數據Distributing By x到2個reducer上:

x1
x2
x4
x3
x1

reducer 1 獲取到:

x1
x2
x1

Reducer 2 獲取到:

x4
x3

注意:具有相同鍵x1的行都被保證分配到相同的reducer中(本例中爲reduce 1),他們不能保證clustered在相鄰位置。
與此相反,如果我們使用Cluster By x,這兩個reducers後面將進一步對x上的行進行排序。
Reducer 1獲取到:

x1
x1
x2

Reducer 2獲取到:

x3
x4

用戶可以指定Distribute By和Sort By,而不是指定Cluster By,因此分區列和sort的列可以不相同。通常情況下分區列是sort列的前綴,但這不是必需的。

SELECT col1, col2 FROM t1 CLUSTER BY col1
SELECT col1, col2 FROM t1 DISTRIBUTE BY col1
SELECT col1, col2 FROM t1 DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC

FROM (
  FROM pv_users
  MAP ( pv_users.userid, pv_users.date )
  USING 'map_script'
  AS c1, c2, c3
  DISTRIBUTE BY c2
  SORT BY c2, c1) map_output
INSERT OVERWRITE TABLE pv_users_reduced
  REDUCE ( map_output.c1, map_output.c2, map_output.c3 )
  USING 'reduce_script'
  AS date, count;

4.5 Hive 的Join操作

4.5.1 Hive的join語法

Hive支持以下的join tables的語法

join_table:
    table_reference [INNER] JOIN table_factor [join_condition]
  | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition
  | table_reference LEFT SEMI JOIN table_reference join_condition
  | table_reference CROSS JOIN table_reference [join_condition] (as of Hive 0.10)
 
table_reference:
    table_factor
  | join_table
 
table_factor:
    tbl_name [alias]
  | table_subquery alias
  | ( table_references )
 
join_condition:
    ON expression

案例:
允許複合join操作

SELECT a.* FROM a JOIN b ON (a.id = b.id)

SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department);

SELECT a.* FROM a LEFT OUTER JOIN b ON (a.id <> b.id)

上面的都是有效的join語句

在一個query語句中可以join多於2個表

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

上面的語句也是一個有效的語句

Hive 將多個表的join操作轉化到一個map/reduce作業,條件是每個表的join子句中使用相同的列。例如:

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

上面的語句被轉換到一個map/reduce作業中,因爲只有b表的key1在join操作中參與了。

另一方面,使用下面的語句時,將有多個map/reduce.

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

上面的操作被轉入到兩個map/reduce作業,因爲b表中的key1列在第一個join條件下使用。b表的key2列在第二個join下執行。第一個map/reduce作業執行a和b的join操作,產生的結果和c表在第二個map/reduce中參與執行。

在join中的每個every/reduce stage,序列中的最後一個表通過reduce進行流處理,而其他表則在其中進行緩存。因此,組織表的時候,使最大的表放在最後面,可以幫助減少reduce中緩存join key的特定值所需的內存。例如:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
所有的這三張表join的時候在一個map/reduce作業中,a表和b表的特定值被緩存在reduce的內存中。然後,對於從c檢索到的每一行,join操作和緩存的行數據進行計算。

類似地:

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)

在計算join操作的時候有兩個map/reduce,第一個步驟是join a和b,緩衝a的值,同時將b的值流到reduce中,第二個map/reduce緩存第一個map/reduce的結果,同時c表的流到reduce中進行處理。

在join的每個map/reduce階段,可以通過指示要流化的表(通過/*+ STREAMTABLE(a) */),例如:

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)

所有三個表的join操作都在一個map/reduce作業中,表b和表c的鍵的特定值的值被緩存在reduce器的內存中,然後,對於從a檢索到的每一行,join操作使用緩衝行進行計算。如果/*+ STREAMTABLE(表名) */ 遺漏了,在join操作的時候,Hive流化最右邊的表。

LEFT,RIGHT和FULL OUTER join存在的目的是爲了在沒有匹配到的ON子句中提供更多的控制,例如:

SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key);

將爲a表中的每一行返回一條記錄,這各輸出的行是b.key = a.key 的a.val,b.val,當沒有對應的b.key的值的時候這個輸出行將輸出a.val,NULL,b的行沒有對應a.key時,鍵值將會被刪除。“FROM a LEFT OUTER JOIN b”語法必須寫在一行上,以便理解它是如何工作的——在這個查詢中,a位於b的左側,因此保留了來自a的所有行。RIGHT OUTER JOIN將保留b中的所有行,而FULL OUTER JOIN將保留a中的所有行和b中的所有行,OUTER JOIN語義應該符合標準SQL規範。

JOIN語句出現在WHERE子句的前面,如果你想限制一個join的輸出,在WHERE子句中需要添加條件,否則就在JOIN子句中。這個問題的一大困惑是分區表:

SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'

上面的sql語句在b上join a,產生一個a.val和b.val的列表。然而,在WHERE子句中,也可以也可以引用a和b表中在join輸出中的其它列,並且過濾它們。然而,當連接中的行找到a表中的key,而在b表沒有找到相應的鍵時,b的所有列都將爲空,包括ds列。這也就是說,你將過濾出所有的行,這些行在join操作輸出中沒有有效b.key。因此在你的LEFT OUTER中要有更好的條件控制。換句話說,如果你在WHERE子句中引用b表中的任何列,在join中的LEFT OUTER部分是不相關的。相反,在使用OUTER JOINing時,使用下面的語法:

SELECT a.val, b.val FROM a LEFT OUTER JOIN b
ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07')

這個join的過濾是預先過濾的,你不會有爲這些擁有有效a.key的行有獲取後置過濾(post-filtering)的麻煩,同樣的邏輯適用於LEFT 或 RIGHT join操作。

JOIN語句是不可以交換的,join是左關聯的,不管它們是LEFT還是RIGHT join語句。

SELECT a.val1, a.val2, b.val, c.val
FROM a
JOIN b ON (a.key = b.key)
LEFT OUTER JOIN c ON (a.key = c.key)

第一個a在b上的join操作,在另外一個表(最終reduce到的表)中丟棄a或b中沒有對應鍵的所有內容(也就是說只有a.key = b.key的所有數據)。這個reduce過的表接着和c表進行join操作。如果在a和c中都存在一個鍵,但是b中不存在,則會得不到不直觀的結果:所有的行(包括a.val1,a.val2,和a.key)在”a JOIN b”的過程中刪除了,因爲它不在b中。在這個結果中沒有a.key在裏面,因此,當它和c執行LEFT OUTER JOIN,c.val不存在,因爲沒有c.key匹配a.key(因爲它已經被刪除了),類似的,如果這是一個RIGHT OUTER JOIN(而不是LEFT),我們將得到一個更奇怪的現象:NULL,NULL,NULL, c.val,因爲當我們指定a.key = c.key進行join的時候,我們drop了所有的不匹配第一個JOIN的數據行。
爲了得到更直觀的效果,我們應該將SQL語句改成 FROM c LEFT OUTER JOIN a ON (c.key = a.key) LEFT OUTER JOIN b ON (c.key = b.key).

LEFT SEMI JOIN(左半連接)是IN/EXISTS子查詢的一種更高效的實現。在Hive 0.13版本IN/NOT IN/EXISTS/NOT EXISTS操作開始支持了,通過子查詢的方式,這樣大多數子查詢就不需要手動執行了。使用左半連接的限制是,右手邊的表只能在JOIN條件(on–子句)中引用,而不能再WHERE或select子句中引用。

SELECT a.key, a.value
FROM a
WHERE a.key in
 (SELECT b.key
  FROM B);
可以被寫成:
SELECT a.key, a.val
FROM a LEFT SEMI JOIN b ON (a.key = b.key)

特點:
1、left semi join 的限制是, JOIN 子句中右邊的表只能在 ON 子句中設置過濾條件,在 WHERE 子句、SELECT 子句或其他地方過濾都不行。
2、left semi join 是隻傳遞表的 join key 給 map 階段,因此left semi join 中最後 select 的結果只許出現左表。
3、因爲 left semi join 是 in(keySet) 的關係,遇到右表重複記錄,左表會跳過,而join 則會一直遍歷。這就導致右表有重複值得情況下 left semi join 只產生一條,join 會產生多條,也會導致 left semi join 的性能更高。
比如以下A表和B表進行join或left semi join,然後select出所有字段,結果區別如下:
在這裏插入圖片描述

MAPJOIN操作
MapJoin是Hive的一種優化操作,其適用於小表JOIN大表的場景,由於表的JOIN操作是在Map端且在內存進行的,所以其並不需要啓動Reduce任務也就不需要經過shuffle階段,從而能在一定程度上節省資源提高JOIN效率。

官方說明:
1、如果join操作的所有表中,有一個表很小,這個作爲一個map任務來執行,查詢語句如下:

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a JOIN b ON a.key = b.key

上面的語句不需要任何一個reducer.對於A的每一個mapper,B都被完全讀取。這裏面的限制是a FULL/RIGHT OUTER JOIN b不可以被執行。

2、如果join的表被分桶過了,並且分桶的列是join的列,一個表中的桶數是另一個表中的桶數的倍數,這些桶之間可以互相連接。如果表A有4個桶,表B有4個桶,使用下面的join操作:

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a JOIN b ON a.key = b.key

上面的語句可以只在mapper中執行,取代了爲A的每個mapper獲取所有的B的,只有需要的桶數據才被獲取到。對於以上的查詢,爲A處理bucket 1的映射程序將只獲取bucket 1 (B)。這不是默認的行爲,需要配置一下參數:

set hive.optimize.bucketmapjoin = true

4、如果join中的表中的join的列被sorted和分桶了。並且他們有相同的桶數,sort-merge可以被執行,對應的桶在mapper是彼此join,如果A和B表都有4個桶,執行以下HiveQL:

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM A a JOIN B b ON a.key = b.key

可以在一個mapper中執行,用於A的桶的映射器將遍歷對應於B的桶。這個不是默認的行爲,下面的參數需要設置:

set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;

4.5.2MapJoin的限制條件

如果被join的所有表中有一個表很小,join操作執行的時候可以只使用一個map。查詢語句是:

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a JOIN b ON a.key = b.key

上面的查詢語句不需要reducer。

下面的情況不支持
Union後面跟着MapJoin
MapJoin後面跟着Lateral View
MapJoin後面跟着Reduce Sink(Group By/Join/Sort By/Cluster By/Distribute By)
MapJoin後面跟着Union
MapJoin後面跟着Join
MapJoin後面跟着MapJoin

配置變量hive.auto.convert.join(如果設置爲true)在運行時自動將連接轉換爲mapjoin(如果可能的話),並且應該使用它而不是/+ mapjoin(表名)/。/+ mapjoin(表名)/應該只用於以下查詢。
1.如果所有輸入都進行了分桶(bucketed)或排序(sorted),則join應轉換爲a bucketized map-side join or bucketized sort-merge join。

考慮不同鍵上多個mapjoin的可能性:

select /*+MAPJOIN(smallTableTwo)*/ idOne, idTwo, value FROM
  ( select /*+MAPJOIN(smallTableOne)*/ idOne, idTwo, value FROM
    bigTable JOIN smallTableOne on (bigTable.idOne = smallTableOne.idOne)                                                  
  ) firstjoin                                                            
  JOIN                                                                 
  smallTableTwo ON (firstjoin.idTwo = smallTableTwo.idTwo)

不支持上述查詢。如果沒有/+MAPJOIN(表名)/,上面的查詢將作爲兩個只包含map-only 作業執行。如果用戶知道這個輸入足夠小,並且可以裝入內存,則可以使用以下可配置參數確保查詢在單個map-reduce作業中執行。
hive.auto.convert.join.noconditionaltask - Whether Hive enable the optimization about converting common join into mapjoin based on the input file size. If this paramater is on, and the sum of size for n-1 of the tables/partitions for a n-way join is smaller than the specified size, the join is directly converted to a mapjoin (there is no conditional task).
hive.auto.convert.join.noconditionaltask.size - If hive.auto.convert.join.noconditionaltask is off, this parameter does not take affect. However, if it is on, and the sum of size for n-1 of the tables/partitions for a n-way join is smaller than this size, the join is directly converted to a mapjoin(there is no conditional task). The default is 10MB.

4.6Union Syntax

語法是:

select_statement UNION [ALL | DISTINCT] select_statement UNION [ALL | DISTINCT] select_statement ...

UNION用於聯合多個select語句的結果到一個結果集裏面。

你可以在一個查詢語句中混合上UNION ALL和UNION DISTINCT

您可以在同一個查詢中混合UNION ALL和UNION DISTINCT。混合UNION類型的處理方式是,一個不同的UNION覆蓋其左側的任何所有UNION。可以通過使用union DISTINCT顯式地生成一個不同的union,也可以使用union DISTINCT隱式地生成一個不同的union,而不使用後面帶有DISTINCT或ALL關鍵字的union。

每個select_statement返回的列的數目和名稱必須相同。否則,將拋出schema錯誤。

4.6.1 FROM子句中的UNION

如果有一些要對UNION的結果額外的處理需求,UNION的整個語句可以嵌入在FROM子句中。如下:

SELECT *
FROM (
  select_statement
  UNION ALL
  select_statement
) unionResult

案例:

SELECT u.id, actions.date
FROM (
    SELECT av.uid AS uid
    FROM action_video av
    WHERE av.date = '2008-06-03'
    UNION ALL
    SELECT ac.uid AS uid
    FROM action_comment ac
    WHERE ac.date = '2008-06-03'
 ) actions JOIN users u ON (u.id = actions.uid)

4.6.2 Unions in DDL and Insert Statements

案例:

SELECT key FROM (SELECT key FROM src ORDER BY key LIMIT 10)subq1
UNION
SELECT key FROM (SELECT key FROM src1 ORDER BY key LIMIT 10)subq2

案例:

SELECT key FROM src
UNION
SELECT key FROM src1 
ORDER BY key LIMIT 10

將UNION的結果插入到表中

INSERT OVERWRITE TABLE target_table
  SELECT name, id, category FROM source_table_1
  UNION ALL
  SELECT name, id, "Category159" FROM source_table_2

4.7 SubQueries

4.7.1 在FROM子句中的Subqueries

語法:

SELECT ... FROM (subquery) name ...
SELECT ... FROM (subquery) AS name ...   (Note: Only valid starting with Hive 0.13.0)

例如:

SELECT col
FROM (
  SELECT a+b AS col
  FROM t1
) t2

帶有UNION ALL的子查詢

SELECT t3.col
FROM (
  SELECT a+b AS col
  FROM t1
  UNION ALL
  SELECT c+d AS col
  FROM t2
) t3

4.7.2 Subqueries in the WHERE Clause

包含IN和NOT IN的情況:

SELECT *
FROM A
WHERE A.a IN (SELECT foo FROM B);

包含EXISTS和NOT EXISTS

SELECT A
FROM T1
WHERE EXISTS (SELECT B FROM T2 WHERE T1.X = T2.Y)

4.8 Import/Export

使用EXPORT命令可以導出一個表或一個分區的數據,並將數據導出到指定的位置。這個輸出路徑可以移動到不同的Hadoop或hive實例中。通過IMPORT命令可以將數據導入到hive中。

導出分區數據的時候,由於原始數據可能位於不同的HDFS位置,因此也是支持導出到分區子集的功能。

導出的元數據存儲在目標目錄中,數據文件存儲在子目錄中。

IMPORT命令在table或partition不存在的時候,它將創建它們。

4.8.1 Export/Import語法

導出語法:

EXPORT TABLE tablename [PARTITION (part_column="value"[, ...])]
  TO 'export_target_path' [ FOR replication('eventid') ]

導入語法:

IMPORT [[EXTERNAL] TABLE new_or_original_tablename [PARTITION (part_column="value"[, ...])]]
  FROM 'source_path'
  [LOCATION 'import_target_path']

4.8.2 Replication語法

Export/import命令當在複製環境中使用時略有不同,並且確定使用該工具在兩個數據倉庫之間使用複製。在大多數情況下,用戶不需要使用這個附加功能,除非手動引導倉庫之間的複製,這樣它可以作爲一個增量複製工具。

他們使用一個特殊的表屬性“repl.last.id”在一個表或分區對象中,確保export/import工具每次複製的數據時最近更新的數據。在導出完成後,會對export的dump文件使用一個id打一個複製標籤,表示在源倉庫集成商單調遞增的。此外,爲複製導出打印的標記不會導致錯誤如果試圖導出一個對象但是標記列當前不存在。

在import方面,沒有語法變化,但是import有一個一般性的標籤對於複製的dump文件,他講檢查要複製的對象是否存在,如果對象已經存在,它檢查對象的repl.last.id屬性,確定是否導入當前對象的最新數據對於目標倉庫,如果更新是最新的,那麼它將複製最新的信息,如果更新已經是很舊的了對於已經存在的對象,那麼更新將被忽略,並且不會產生錯誤。

對於那些使用export進行首次手動引導用例,用戶推薦使用“引導”標籤,

4.8.3示例

1.簡單導出和導出

export table department to 'hdfs_exports_location/department';

import from 'hdfs_exports_location/department';

具體導出案例:
在這裏插入圖片描述
在這裏插入圖片描述
頁面中查看:
在這裏插入圖片描述

具體導入案例:
在這裏插入圖片描述
2.在import時重命名錶

export table department to 'hdfs_exports_location/department';

import table imported_dept from 'hdfs_exports_location/department';

3.導出分區並導入

export table employee partition (emp_country="in", emp_state="ka") to 'hdfs_exports_location/employee';

import from 'hdfs_exports_location/employee';
  1. 導出表並且導入到分區表分區
export table employee to 'hdfs_exports_location/employee';

import table employee partition (emp_country="us", emp_state="tn") from 'hdfs_exports_location/employee';

5.指定導入位置

export table department to 'hdfs_exports_location/department';

import table department from 'hdfs_exports_location/department'
       location 'import_target_location/department';
  1. 導入作爲一個外部表
export table department to 'hdfs_exports_location/department';

import external table department from 'hdfs_exports_location/department';

打個賞唄,您的支持是我堅持寫好博文的動力。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章