爲了演示查詢操做,這裏須要預先建立三張表,並加載測試數據。git
數據文件 emp.txt 和 dept.txt 能夠從本倉庫的resources 目錄下載。github
-- 建表語句 CREATE TABLE emp( empno INT, -- 員工表編號 ename STRING, -- 員工姓名 job STRING, -- 職位類型 mgr INT, hiredate TIMESTAMP, --僱傭日期 sal DECIMAL(7,2), --工資 comm DECIMAL(7,2), deptno INT) --部門編號 ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; --加載數據 LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp;
-- 建表語句 CREATE TABLE dept( deptno INT, --部門編號 dname STRING, --部門名稱 loc STRING --部門所在的城市 ) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; --加載數據 LOAD DATA LOCAL INPATH "/usr/file/dept.txt" OVERWRITE INTO TABLE dept;
這裏須要額外建立一張分區表,主要是爲了演示分區查詢:sql
CREATE EXTERNAL TABLE emp_ptn( empno INT, ename STRING, job STRING, mgr INT, hiredate TIMESTAMP, sal DECIMAL(7,2), comm DECIMAL(7,2) ) PARTITIONED BY (deptno INT) -- 按照部門編號進行分區 ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; --加載數據 LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=20) LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=30) LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=40) LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=50)
-- 查詢表中所有數據 SELECT * FROM emp;
-- 查詢 10 號部門中員工編號大於 7782 的員工信息 SELECT * FROM emp WHERE empno > 7782 AND deptno = 10;
Hive 支持使用 DISTINCT 關鍵字去重。數據庫
-- 查詢全部工做類型 SELECT DISTINCT job FROM emp;
分區查詢 (Partition Based Queries),能夠指定某個分區或者分區範圍。apache
-- 查詢分區表中部門編號在[20,40]之間的員工 SELECT emp_ptn.* FROM emp_ptn WHERE emp_ptn.deptno >= 20 AND emp_ptn.deptno <= 40;
-- 查詢薪資最高的 5 名員工 SELECT * FROM emp ORDER BY sal DESC LIMIT 5;
Hive 支持使用 GROUP BY 進行分組聚合操做。緩存
set hive.map.aggr=true; -- 查詢各個部門薪酬綜合 SELECT deptno,SUM(sal) FROM emp GROUP BY deptno;
hive.map.aggr
控制程序如何進行聚合。默認值爲 false。若是設置爲 true,Hive 會在 map 階段就執行一次聚合。這能夠提升聚合效率,但須要消耗更多內存。性能
可使用 ORDER BY 或者 Sort BY 對查詢結果進行排序,排序字段能夠是整型也能夠是字符串:若是是整型,則按照大小排序;若是是字符串,則按照字典序排序。ORDER BY 和 SORT BY 的區別以下:測試
因爲 ORDER BY 的時間可能很長,若是你設置了嚴格模式 (hive.mapred.mode = strict),則其後面必須再跟一個 limit
子句。大數據
注 :hive.mapred.mode 默認值是 nonstrict ,也就是非嚴格模式。優化
-- 查詢員工工資,結果按照部門升序,按照工資降序排列 SELECT empno, deptno, sal FROM emp ORDER BY deptno ASC, sal DESC;
可使用 HAVING 對分組數據進行過濾。
-- 查詢工資總和大於 9000 的全部部門 SELECT deptno,SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal)>9000;
默認狀況下,MapReduce 程序會對 Map 輸出結果的 Key 值進行散列,並均勻分發到全部 Reducer 上。若是想要把具備相同 Key 值的數據分發到同一個 Reducer 進行處理,這就須要使用 DISTRIBUTE BY 字句。
須要注意的是,DISTRIBUTE BY 雖然能保證具備相同 Key 值的數據分發到同一個 Reducer,可是不能保證數據在 Reducer 上是有序的。狀況以下:
把如下 5 個數據發送到兩個 Reducer 上進行處理:
k1 k2 k4 k3 k1
Reducer1 獲得以下亂序數據:
k1 k2 k1
Reducer2 獲得數據以下:
k4 k3
若是想讓 Reducer 上的數據時有序的,能夠結合 SORT BY
使用 (示例以下),或者使用下面咱們將要介紹的 CLUSTER BY。
-- 將數據按照部門分發到對應的 Reducer 上處理 SELECT empno, deptno, sal FROM emp DISTRIBUTE BY deptno SORT BY deptno ASC;
若是 SORT BY
和 DISTRIBUTE BY
指定的是相同字段,且 SORT BY 排序規則是 ASC,此時可使用 CLUSTER BY
進行替換,同時 CLUSTER BY
能夠保證數據在全局是有序的。
SELECT empno, deptno, sal FROM emp CLUSTER BY deptno ;
Hive 支持內鏈接,外鏈接,左外鏈接,右外鏈接,笛卡爾鏈接,這和傳統數據庫中的概念是一致的,能夠參見下圖。
須要特別強調:JOIN 語句的關聯條件必須用 ON 指定,不能用 WHERE 指定,不然就會先作笛卡爾積,再過濾,這會致使你得不到預期的結果 (下面的演示會有說明)。
-- 查詢員工編號爲 7369 的員工的詳細信息 SELECT e.*,d.* FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE empno=7369; --若是是三表或者更多表鏈接,語法以下 SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
LEFT OUTER JOIN 和 LEFT JOIN 是等價的。
-- 左鏈接 SELECT e.*,d.* FROM emp e LEFT OUTER JOIN dept d ON e.deptno = d.deptno;
--右鏈接 SELECT e.*,d.* FROM emp e RIGHT OUTER JOIN dept d ON e.deptno = d.deptno;
執行右鏈接後,因爲 40 號部門下沒有任何員工,因此此時員工信息爲 NULL。這個查詢能夠很好的複述上面提到的——JOIN 語句的關聯條件必須用 ON 指定,不能用 WHERE 指定。你能夠把 ON 改爲 WHERE,你會發現不管如何都查不出 40 號部門這條數據,由於笛卡爾運算不會有 (NULL, 40) 這種狀況。
SELECT e.*,d.* FROM emp e FULL OUTER JOIN dept d ON e.deptno = d.deptno;
LEFT SEMI JOIN (左半鏈接)是 IN/EXISTS 子查詢的一種更高效的實現。
-- 查詢在紐約辦公的全部員工信息 SELECT emp.* FROM emp LEFT SEMI JOIN dept ON emp.deptno = dept.deptno AND dept.loc="NEW YORK"; --上面的語句就等價於 SELECT emp.* FROM emp WHERE emp.deptno IN (SELECT deptno FROM dept WHERE loc="NEW YORK");
笛卡爾積鏈接,這個鏈接平常的開發中可能不多遇到,且性能消耗比較大,基於這個緣由,若是在嚴格模式下 (hive.mapred.mode = strict),Hive 會阻止用戶執行此操做。
SELECT * FROM emp JOIN dept;
在多表進行聯結的時候,若是每一個 ON 字句都使用到共同的列(以下面的 b.key
),此時 Hive 會進行優化,將多表 JOIN 在同一個 map / reduce 做業上進行。同時假定查詢的最後一個表(以下面的 c 表)是最大的一個表,在對每行記錄進行 JOIN 操做時,它將嘗試將其餘的表緩存起來,而後掃描最後那個表進行計算。所以用戶須要保證查詢的表的大小從左到右是依次增長的。
`SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key) JOIN c ON (c.key = b.key)`
而後,用戶並不是須要老是把最大的表放在查詢語句的最後面,Hive 提供了 /*+ STREAMTABLE() */
標誌,用於標識最大的表,示例以下:
SELECT /*+ STREAMTABLE(d) */ e.*,d.* FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE job='CLERK';
若是全部表中只有一張表是小表,那麼 Hive 把這張小表加載到內存中。這時候程序會在 map 階段直接拿另一個表的數據和內存中表數據作匹配,因爲在 map 就進行了 JOIN 操做,從而能夠省略 reduce 過程,這樣效率能夠提高不少。Hive 中提供了 /*+ MAPJOIN() */
來標記小表,示例以下:
SELECT /*+ MAPJOIN(d) */ e.*,d.* FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE job='CLERK';
查看當前數據庫:
SELECT current_database()
在上面演示的語句中,大多數都會觸發 MapReduce, 少部分不會觸發,好比 select * from emp limit 5
就不會觸發 MR,此時 Hive 只是簡單的讀取數據文件中的內容,而後格式化後進行輸出。在須要執行 MapReduce 的查詢中,你會發現執行時間可能會很長,這時候你能夠選擇開啓本地模式。
--本地模式默認關閉,須要手動開啓此功能 SET hive.exec.mode.local.auto=true;
啓用後,Hive 將分析查詢中每一個 map-reduce 做業的大小,若是知足如下條件,則能夠在本地運行它:
由於咱們測試的數據集很小,因此你再次去執行上面涉及 MR 操做的查詢,你會發現速度會有顯著的提高。
更多大數據系列文章能夠參見 GitHub 開源項目: 大數據入門指南