6W字的Hive講解只爲你更懂它

高清思維導圖已同步Git:https://github.com/SoWhat1412/xmindfile

在這裏插入圖片描述

1. Hive 入門

什麼是Hive

Hive:由Facebook開源用於解決海量結構化日誌的數據統計。

Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射爲一張表,並提供類SQL查詢功能。
本質:將HQL轉化成MapReduce程序
在這裏插入圖片描述
Hive特性:

  • Hive處理的數據存儲在HDFS
  • Hive分析數據底層的實現是MapReduce
  • 執行程序運行在Yarn
Hive的優缺點

優點:

  1. 操作接口採用類SQL語法,提供快速開發的能力(簡單、容易上手)。
  2. 避免了去寫MapReduce,減少開發人員的學習成本
  3. Hive的執行延遲比較高,因此Hive常用於數據分析,對實時性要求不高的場合。
  4. Hive優勢在於處理大數據,對於處理小數據沒有優勢,因爲Hive的執行延遲比較高。
  5. Hive支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數。

缺點:

  1. Hive的HQL表達能力有限
  • 迭代式算法無法表達
  • 數據挖掘方面不擅長
  1. Hive的效率比較低
  • Hive自動生成的MapReduce作業,通常情況下不夠智能化
  • Hive調優比較困難,粒度較粗
Hive架構原理

在這裏插入圖片描述

  1. 用戶接口:Client

CLI(hive shell)、JDBC/ODBC(java訪問hive)、WEBUI(瀏覽器訪問hive)

  1. 元數據:Metastore

元數據包括:表名、表所屬的數據庫(默認是default)、表的擁有者、列/分區字段、表的類型(是否是外部表)、表的數據所在目錄等;
默認存儲在自帶的derby數據庫中,推薦使用MySQL存儲Metastore

  1. Hadoop

使用HDFS進行存儲,使用MapReduce進行計算。

  1. 驅動器:Driver
  1. 解析器(SQL Parser):將SQL字符串轉換成抽象語法樹AST,這一步一般都用第三方工具庫完成,比如antlr;對AST進行語法分析,比如表是否存在、字段是否存在、SQL語義是否有誤。
  2. 編譯器(Physical Plan):將AST編譯生成邏輯執行計劃。
  3. 優化器(Query Optimizer):對邏輯執行計劃進行優化。
  4. 執行器(Execution):把邏輯執行計劃轉換成可以運行的物理計劃。對於Hive來說,就是MR/Spark。

在這裏插入圖片描述
Hive通過給用戶提供的一系列交互接口,接收到用戶的指令(SQL),使用自己的Driver,結合元數據(MetaStore),將這些指令翻譯成MapReduce,提交到Hadoop中執行,最後,將執行返回的結果輸出到用戶交互接口。

Hive和數據庫比較

由於 Hive 採用了類SQL 的查詢語言 HQL(Hive Query Language),因此很容易將 Hive 理解爲數據庫。其實從結構上來看,Hive 和數據庫除了擁有類似的查詢語言,再無類似之處。本文將從多個方面來闡述 Hive 和數據庫的差異。數據庫可以用在 Online 的應用中,但是Hive 是爲數據倉庫而設計的,清楚這一點,有助於從應用角度理解 Hive 的特性。

查詢語言

由於SQL被廣泛的應用在數據倉庫中,因此,專門針對Hive的特性設計了類SQL的查詢語言HQL。熟悉SQL開發的開發者可以很方便的使用Hive進行開發。

數據存儲位置

Hive 是建立在 Hadoop 之上的,所有 Hive 的數據都是存儲在 HDFS 中的。而數據庫則可以將數據保存在塊設備或者本地文件系統中。

數據更新

由於Hive是針對數據倉庫應用設計的,而數據倉庫的內容是讀多寫少的。因此,Hive中不建議對數據的改寫,所有的數據都是在加載的時候確定好的。而數據庫中的數據通常是需要經常進行修改的,因此可以使用 INSERT INTO … VALUES 添加數據,使用 UPDATE … SET修改數據。

索引

Hive在加載數據的過程中不會對數據進行任何處理,甚至不會對數據進行掃描,因此也沒有對數據中的某些Key建立索引。Hive要訪問數據中滿足條件的特定值時,需要暴力掃描整個數據,因此訪問延遲較高。由於 MapReduce 的引入, Hive 可以並行訪問數據,因此即使沒有索引,對於大數據量的訪問,Hive 仍然可以體現出優勢。數據庫中,通常會針對一個或者幾個列建立索引,因此對於少量的特定條件的數據的訪問,數據庫可以有很高的效率,較低的延遲。由於數據的訪問延遲較高,決定了 Hive 不適合在線數據查詢

執行

Hive中大多數查詢的執行是通過 Hadoop 提供的 MapReduce 來實現的。而數據庫通常有自己的執行引擎。

執行延遲

Hive 在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高。另外一個導致 Hive 執行延遲高的因素是 MapReduce框架。由於MapReduce 本身具有較高的延遲,因此在利用MapReduce 執行Hive查詢時,也會有較高的延遲。相對的,數據庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過數據庫的處理能力的時候,Hive的並行計算顯然能體現出優勢。

可擴展性

由於Hive是建立在Hadoop之上的,因此Hive的可擴展性是和Hadoop的可擴展性是一致的(世界上最大的Hadoop 集羣在 Yahoo!,2009年的規模在4000 臺節點左右)。而數據庫由於 ACID 語義的嚴格限制,擴展行非常有限。目前最先進的並行數據庫 Oracle 在理論上的擴展能力也只有100臺左右。

數據規模

由於Hive建立在集羣上並可以利用MapReduce進行並行計算,因此可以支持很大規模的數據;對應的,數據庫可以支持的數據規模較小。

2. Hive 安裝

Hive安裝地址
  1. Hive官網地址

http://hive.apache.org/

  1. 文檔查看地址

https://cwiki.apache.org/confluence/display/Hive/GettingStarted

  1. 下載地址

http://archive.apache.org/dist/hive/

  1. github地址

https://github.com/apache/hive

Hive安裝部署

1. Hive安裝及配置

  1. 把apache-hive-1.2.1-bin.tar.gz上傳到linux的/opt/software目錄下
  2. 解壓apache-hive-1.2.1-bin.tar.gz到/opt/module/目錄下面

[atguigu@hadoop102 software]$ tar -zxvf apache-hive-1.2.1-bin.tar.gz -C /opt/module/

  1. 修改apache-hive-1.2.1-bin.tar.gz的名稱爲hive

[atguigu@hadoop102 module]$ mv apache-hive-1.2.1-bin/ hive

  1. 修改/opt/module/hive/conf目錄下的hive-env.sh.template名稱爲hive-env.sh

[atguigu@hadoop102 conf]$ mv hive-env.sh.template hive-env.sh

  1. 配置hive-env.sh文件
    配置HADOOP_HOME路徑: export HADOOP_HOME=/opt/module/hadoop-2.7.2
    配置HIVE_CONF_DIR路徑: export HIVE_CONF_DIR=/opt/module/hive/conf

2. Hadoop集羣配置

  1. 必須啓動 hdfs 和 yarn

[atguigu@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
[atguigu@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh

  1. 在HDFS上創建/tmp和/user/hive/warehouse兩個目錄並修改他們的同組權限可寫

[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -mkdir /tmp
[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -mkdir -p /user/hive/warehouse
[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -chmod g+w /tmp
[atguigu@hadoop102 hadoop-2.7.2]$ bin/hadoop fs -chmod g+w /user/hive/warehouse

3. Hive基本操作

  1. 啓動hive

[atguigu@hadoop102 hive]$ bin/hive

  1. 查看數據庫

hive> show databases;

  1. 打開默認數據庫

hive> use default;

  1. 顯示default數據庫中的表

hive> show tables;

  1. 創建一張表

hive> create table student(id int, name string);

  1. 顯示數據庫中有幾張表

hive> show tables;

  1. 查看錶的結構

hive> desc student;

  1. 向表中插入數據

hive> insert into student values(1000,“ss”);

  1. 查詢表中數據

hive> select * from student;

  1. 退出hive

hive> quit;

4. 將本地文件導入Hive案例
需求:將本地 /opt/module/datas/student.txt 這個目錄下的數據導入到hive的student(id int, name string)表中。
1.數據準備(注意以tab鍵間隔)

1001	zhangshan
1002	lishi
1003	zhaoliu
  1. 創建student表, 並聲明文件分隔符 ’\t’

hive> create table student(id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’;

  1. 加載/opt/module/datas/student.txt 文件到student數據庫表中。

hive> load data local inpath ‘/opt/module/datas/student.txt’ into table student;

  1. Hive查詢結果

hive> select * from student;
OK
1001 zhangshan
1002 lishi
1003 zhaoliu
Time taken: 0.266 seconds, Fetched: 3 row(s)

PS:如果我們準備好符合table要求的數據 通過hadoop dfs -put filename hdfspwd 後 put上的數據也是可以在hive中查詢出來的!
在這裏插入圖片描述

5. 遇到的問題
打開一個客戶端窗口啓動hive,會產生java.sql.SQLException異常。

Exception in thread “main” java.lang.RuntimeException: java.lang.RuntimeException:
Unable to instantiate
org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient

原因:Metastore默認存儲在自帶的derby數據庫中,derby是單客戶關聯的。推薦使用MySQL存儲Metastore;

MySQL安裝
  1. 安裝包準備
    查看mysql是否安裝,如果安裝了,卸載mysql

root@hadoop102 桌面]# rpm -qa|grep mysql
mysql-libs-5.1.73-7.el6.x86_64
[root@hadoop102 桌面]# rpm -e --nodeps mysql-libs-5.1.73-7.el6.x86_64

2.解壓mysql-libs.zip文件到當前目錄

[root@hadoop102 software]# unzip mysql-libs.zip
[root@hadoop102 software]# ls
mysql-libs.zip
mysql-libs
進入到mysql-libs文件夾下
[root@hadoop102 mysql-libs]# ls -l
總用量 76048
-rw-r–r--. 1 root root 18509960 3月 26 2015 MySQL-client-5.6.24-1.el6.x86_64.rpm
-rw-r–r--. 1 root root 3575135 12月 1 2013 mysql-connector-java-5.1.27.tar.gz
-rw-r–r--. 1 root root 55782196 3月 26 2015 MySQL-server-5.6.24-1.el6.x86_64.rpm

  1. 安裝MySql服務器
    安裝mysql服務端

[root@hadoop102 mysql-libs]# rpm -ivh MySQL-server-5.6.24-1.el6.x86_64.rpm
查看產生的隨機密碼
[root@hadoop102 mysql-libs]# cat /root/.mysql_secret
OEXaQuS8IWkG19Xs
查看mysql狀態
[root@hadoop102 mysql-libs]# service mysql status
啓動mysql
[root@hadoop102 mysql-libs]# service mysql start

  1. 安裝MySql客戶端

安裝mysql客戶端
[root@hadoop102 mysql-libs]# rpm -ivh MySQL-client-5.6.24-1.el6.x86_64.rpm
連接 mysql
[root@hadoop102 mysql-libs]# mysql -uroot -pOEXaQuS8IWkG19Xs
修改密碼
mysql>SET PASSWORD=PASSWORD(‘000000’);
退出mysql
mysql>exit

  1. MySql中user表中主機配置
    配置只要是root用戶+密碼,在任何主機上都能登錄MySQL數據庫。
    進入mysql

[root@hadoop102 mysql-libs]# mysql -uroot -p000000
顯示數據庫
mysql>show databases;
使用mysql數據庫
mysql>use mysql;
展示mysql數據庫中的所有表
mysql>show tables;
展示user表的結構
mysql>desc user;
查詢user表
mysql>select User, Host, Password from user;
修改user表,把Host表內容修改爲%
mysql>update user set host=’%’ where host=‘localhost’;
刪除root用戶的其他host
mysql>delete from user where Host=‘hadoop102’;
mysql>delete from user where Host=‘127.0.0.1’;
mysql>delete from user where Host=’::1’;
刷新
mysql>flush privileges;
退出
mysql>quit;

Hive元數據配置到MySql

驅動拷貝

在/opt/software/mysql-libs目錄下解壓mysql-connector-java-5.1.27.tar.gz驅動包
[root@hadoop102 mysql-libs]# tar -zxvf mysql-connector-java-5.1.27.tar.gz
拷貝/opt/software/mysql-libs/mysql-connector-java-5.1.27目錄下的mysql-connector-java-5.1.27-bin.jar到/opt/module/hive/lib/
[root@hadoop102 mysql-connector-java-5.1.27]# cp mysql-connector-java-5.1.27-bin.jar /opt/module/hive/lib/

配置Metastore到MySql

在/opt/module/hive/conf目錄下創建一個hive-site.xml

[atguigu@hadoop102 conf]$ touch hive-site.xml
[atguigu@hadoop102 conf]$ vi hive-site.xml

2.根據安裝指南 配置參數,拷貝數據到hive-site.xml文件中

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
	<property>
	  <name>javax.jdo.option.ConnectionURL</name>
	  <value>jdbc:mysql://hadoop102:3306/metastore?createDatabaseIfNotExist=true</value>
	  <description>JDBC connect string for a JDBC metastore</description>
	</property>

	<property>
	  <name>javax.jdo.option.ConnectionDriverName</name>
	  <value>com.mysql.jdbc.Driver</value>
	  <description>Driver class name for a JDBC metastore</description>
	</property>

	<property>
	  <name>javax.jdo.option.ConnectionUserName</name>
	  <value>root</value>
	  <description>username to use against metastore database</description>
	</property>

	<property>
	  <name>javax.jdo.option.ConnectionPassword</name>
	  <value>000000</value>
	  <description>password to use against metastore database</description>
	</property>
</configuration>

配置完畢後,如果啓動hive異常,可以重新啓動虛擬機(重啓後,別忘了啓動hadoop集羣)。

  1. 多窗口啓動Hive測試
    先啓動MySQL

[atguigu@hadoop102 mysql-libs]$ mysql -uroot -p000000
查看有幾個數據庫
mysql> show databases;
±-------------------+
| Database |
±-------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
±-------------------+

再次打開多個窗口,分別啓動hive

[atguigu@hadoop102 hive]$ bin/hive

3.啓動hive後,回到MySQL窗口查看數據庫,顯示增加了metastore數據庫

mysql> show databases;
±-------------------+
| Database |
±-------------------+
| information_schema |
| metastore |
| mysql |
| performance_schema |
| test |
±-------------------+

Hive 訪問
  1. hive 命令行模式,直接輸入/hive/bin/hive的執行程序,或者輸入 hive --service cli

用於linux平臺命令行查詢,查詢語句基本跟mysql查詢語句類似

  1. hive web界面的啓動方式,hive --service hwi

用於通過瀏覽器來訪問hive,感覺沒多大用途

  1. hive 遠程服務 (端口號10000) 啓動方式,./hive --service hiveserver >/dev/null 2>/dev/null &

用java等程序實現通過jdbc等驅動的訪問hive就用這種起動方式了,這個是程序員最需要的方式了

  1. 遠程服務方式登陸hive
    啓動beeline

[atguigu@hadoop102 hive]$ bin/beeline
Beeline version 1.2.1 by Apache Hive
beeline>

  1. 連接hiveserver2

beeline> !connect jdbc:hive2://hadoop102:10000(回車)
Connecting to jdbc:hive2://hadoop102:10000
Enter username for jdbc:hive2://hadoop102:10000: 用戶名(回車)
Enter password for jdbc:hive2://hadoop102:10000: 密碼(直接回車)
Connected to: Apache Hive (version 1.2.1)
Driver: Hive JDBC (version 1.2.1)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://hadoop102:10000> show databases;
±---------------±-+
| database_name |
±---------------±-+
| default |
| hive_db2 |
±---------------±-+

beeline 登陸 Hive

  1. beeline
  2. !connect jdbc:hive2://IP:Port(默認10000) 比如 !connect jdbc:hive2://127.0.0.1:10000
  3. 輸入賬號 跟密碼
  4. 如下可導出數據
    beeline -u jdbc:hive2://IP:Port -n 賬戶 -p 密碼 --verbose=true --showHeader=true --outputformat=csv --color=true -e "use db;select * from ${table_name} " >> dirpath/dir_path/dir/$table_name
Hive常用交互命令
hive -help
usage: hive
 -d,--define <key=value>          Variable subsitution to apply to hive
                                  commands. e.g. -d A=B or --define A=B
    --database <databasename>     Specify the database to use
 -e <quoted-query-string>         SQL from command line
 -f <filename>                    SQL from files
 -H,--help                        Print help information
    --hiveconf <property=value>   Use value for given property
    --hivevar <key=value>         Variable subsitution to apply to hive
                                  commands. e.g. --hivevar A=B
 -i <filename>                    Initialization SQL file
 -S,--silent                      Silent mode in interactive shell
 -v,--verbose                     Verbose mode (echo executed SQL to the
                                  console)
  1. -e 不進入hive的交互窗口執行sql語句
    [atguigu@hadoop102 hive]$ bin/hive -e “select id from student;”
  2. -f 執行腳本中sql語句

在/opt/module/datas目錄下創建 hivef.sql 文件
[atguigu@hadoop102 datas]$ touch hivef.sql
文件中寫入正確的sql語句: select *from student;
執行文件中的sql語句: bin/hive -f /opt/module/datas/hivef.sql
執行文件中的sql語句並將結果寫入文件中
[atguigu@hadoop102 hive]$ bin/hive -f /opt/module/datas/hivef.sql > /opt/module/datas/hive_result.txt

Hive其他命令操作
  1. 退出hive窗口:

hive(default)>exit;
hive(default)>quit;
在新版的hive中沒區別了,在以前的版本是有的:
exit:先隱性提交數據,再退出;
quit:不提交數據,退出;

  1. 在hive cli命令窗口中如何查看hdfs文件系統

hive(default)> dfs -ls /;

  1. 在hive cli命令窗口中如何查看本地文件系統

hive(default)> ! ls /opt/module/datas;

  1. 查看在hive中輸入的所有歷史命令

[atguigu@hadoop102 ~]$ cd;cat .hivehistory

Hive數據倉庫位置配置
  1. Default數據倉庫的最原始位置是在hdfs上的:/user/hive/warehouse 路徑下。
  2. 在倉庫目錄下,沒有對默認的數據庫default創建文件夾。如果某張表屬於default數據庫,直接在數據倉庫目錄下創建一個文件夾。
show create table presto_queries  default 下面的table存儲
LOCATION
  'hdfs://cluster/user/hive/warehouse/presto_queries'
  
show create table Mytest  dm_kg 下面table存儲
LOCATION
  'hdfs://cluster/user/hive/warehouse/dm_kg.db/similar_phonebook_result'
  1. 修改default數據倉庫原始位置(將hive-default.xml.template如下配置信息拷貝到hive-site.xml文件中)。
<property>
	<name>hive.metastore.warehouse.dir</name>
	<value>/user/hive/warehouse</value> 裏面有 若干的 db,db裏面又有tables
	<description>location of default database for the warehouse</description>
</property>

配置同組用戶有執行權限

bin/hdfs dfs -chmod g+w /user/hive/warehouse

Hive顯示當前所在db名跟查詢字段名

Hive運行日誌信息配置

1.Hive的 log 默認存放在 /tmp/用戶/hive.log目錄下(當前用戶名下)
2.修改hive的log存放日誌到 /opt/module/hive/logs

修改/opt/module/hive/conf/hive-log4j.properties.template文件名稱爲 hive-log4j.properties
[atguigu@hadoop102 conf]$ mv hive-log4j.properties.template hive-log4j.properties
在hive-log4j.properties文件中修改log存放位置
hive.log.dir=/opt/module/hive/logs

參數配置方式

查看當前所有的配置信息

hive>set;
一堆kv對

參數的配置三種方式

  1. 配置文件方式

默認配置文件:hive-default.xml
用戶自定義配置文件:hive-site.xml
注意:用戶自定義配置會覆蓋默認配置。另外,Hive也會讀入Hadoop的配置,因爲Hive是作爲Hadoop的客戶端啓動的,Hive的配置會覆蓋Hadoop的配置。配置文件的設定對本機啓動的所有Hive進程都有效

  1. 命令行參數方式
    啓動Hive時,可以在命令行添加-hiveconf param=value 來設定參數。

[atguigu@hadoop103 hive]$ bin/hive -hiveconf mapred.reduce.tasks=10;
注意:僅對本次hive啓動有效

查看參數設置:

hive (default)> set mapred.reduce.tasks;

  1. 參數聲明方式

可以在HQL中使用SET關鍵字設定參數
例如:
hive (default)> set mapred.reduce.tasks=100;
注意:僅對本次hive啓動有效
查看參數設置
hive (default)> set mapred.reduce.tasks;
上述三種設定方式的優先級依次遞增。即配置文件 < 命令行參數 < 參數聲明。注意某些系統級的參數,例如log4j相關的設定,必須用前兩種方式設定,因爲那些參數的讀取在會話建立以前已經完成了。

3. Hive 數據格式

基本數據類型
Hive數據類型 Java數據類型 長度 例子
TINYINT byte 1byte有符號整數 20
SMALINT short 2byte有符號整數 20
INT int 4byte 有符號整數 20
BIGINT long 8byte有符號整數 20
BOOLEAN boolean 布爾類型,true或者false TRUE FALSE
FLOAT float 單精度浮點數 3.14159
DOUBLE double 雙精度浮點數 3.14159
STRING string 字符系列。可以指定字符集。可以使用單引號或者雙引號。 ‘now is the time’ “for all good men”
TIMESTAMP 時間類型
BINARY 字節數組

對於Hive的String類型相當於數據庫的varchar類型,該類型是一個可變的字符串,不過它不能聲明其中最多能存儲多少個字符,理論上它可以存儲2GB的字符數。

集合數據類型
數據類型 描述 語法示例
STRUCT 和c語言中的struct類似,都可以通過“點”符號訪問元素內容。例如,如果某個列的數據類型是STRUCT{first STRING, last STRING},那麼第1個元素可以通過字段.first來引用。 struct()
MAP MAP是一組鍵-值對元組集合,使用數組表示法可以訪問數據。例如,如果某個列的數據類型是MAP,其中鍵->值對是’first’->’John’和’last’->’Doe’,那麼可以通過字段名[‘last’] 獲取最後一個元素 map()
ARRAY 數組是一組具有相同類型和名稱的變量的集合。這些變量稱爲數組的元素,每個數組元素都有一個編號,編號從零開始。例如,數組值爲[‘John’, ‘Doe’],那麼第2個元素可以通過 數組名[1] 進行引用。 Array()

Hive有三種複雜數據類型ARRAYMAPSTRUCT。ARRAY和MAP與Java中的Array和Map類似,而STRUCT與C語言中的Struct類似,它封裝了一個命名字段集合,複雜數據類型允許任意層次的嵌套。

demo:
假設某表有如下一行,我們用JSON格式來表示其數據結構。在Hive下訪問的格式爲

{
    "name": "songsong",
    "friends": ["bingbing" , "lili"] ,       //列表Array, 
    "children": {                      //鍵值Map,
        "xiao song": 18 ,
        "xiaoxiao song": 19
    }
    "address": {                      //結構Struct,
        "street": "hui long guan" ,
        "city": "beijing" 
    }
}

基於上述數據結構,我們在Hive裏創建對應的表,並導入數據。 創建本地測試文件test.txt

songsong,bingbing_lili,xiao song:18_xiaoxiao song:19,hui long guan_beijing
yangyang,caicai_susu,xiao yang:18_xiaoxiao yang:19,chao yang_beijing

注意:MAP,STRUCT和ARRAY裏的元素間關係都可以用同一個字符表示,這裏用 _ 。

create table test(
name string,
friends array<string>,
children map<string, int>,
address struct<street:string, city:string>
)
row format delimited fields terminated by ','
collection items terminated by '_'
map keys terminated by ':'
lines terminated by '\n';

字段解釋:

代碼 含義
row format delimited fields terminated by ‘,’ 列分隔符
collection items terminated by ‘_’ MAP STRUCT 和 ARRAY 的分隔符(數據分割符號)
map keys terminated by ‘:’ MAP中的key與value的分隔符
lines terminated by ‘\n’; 行分隔符

導入本地文本數據到測試表

hive (default)> load data local inpath ‘/opt/module/datas/test.txt’into table test

訪問三種集合列裏的數據,以下分別是ARRAY,MAP,STRUCT的訪問方式

hive (default)> select friends[1],children[‘xiao song’],address.city from test where name=“songsong”;
_c0 _c1 city
lili 18 beijing
Time taken: 0.076 seconds, Fetched: 1 row(s)

如果是導入HDFS上的文件到一個table,則意味是是將將HDFS文件進行了mv

load data inpath ‘/stu2.txt’ into table stu;
實際是在HDFS上執行的 mv /stu2.txt stu_table_path

類型轉化

Hive的原子數據類型是可以進行隱式轉換的,類似於Java的類型轉換,例如某表達式使用INT類型,TINYINT會自動轉換爲INT類型,但是Hive不會進行反向轉化,例如,某表達式使用TINYINT類型,INT不會自動轉換爲TINYINT類型,它會返回錯誤,除非使用CAST操作。

  1. 隱式類型轉換規則如下

(1)任何整數類型都可以隱式地轉換爲一個範圍更廣的類型,如TINYINT可以轉換成INT,INT可以轉換成BIGINT。
(2)所有整數類型、FLOAT和STRING類型都可以隱式地轉換成DOUBLE。
(3)TINYINT、SMALLINT、INT都可以轉換爲FLOAT。
(4)BOOLEAN類型不可以轉換爲任何其它的類型。

  1. 可以使用CAST操作顯示進行數據類型轉換
    例如CAST('1' AS INT)將把字符串’1’ 轉換成整數1;如果強制類型轉換失敗,如執行CAST(‘X’ AS INT),表達式返回空值 NULL

4. DDL數據定義(重點)

適用範圍:對數據庫中的某些對象(例如,database,table)進行管理,如Create,Alter和Drop.truncate
DDL操作是隱性提交的,不能rollback!

數據庫操作

1. 創建數據庫

創建一個數據庫,數據庫在HDFS上的默認存儲路徑是/user/hive/warehouse/*.db

hive (default)> create database db_hive;

避免要創建的數據庫已經存在錯誤,增加if not exists判斷。(標準寫法)

hive (default)> create database db_hive;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. Database db_hive already exists
hive (default)> create database if not exists db_hive;

創建一個數據庫,指定數據庫在 HDFS 上存放的位置

hive (default)> create database db_hive2 location ‘/db_hive2.db’;

在這裏插入圖片描述

2. 查詢數據庫

顯示數據庫

hive> show databases;

過濾顯示查詢的數據庫

hive> show databases like ‘db_hive*’;
db_hive
db_hive_1

顯示數據庫信息

hive> desc database db_hive;
db_hive hdfs://hadoop102:9000/user/hive/warehouse/db_hive.db atguigu USER

顯示數據庫詳細信息,extended

hive> desc database extended db_hive;
db_hive hdfs://hadoop102:9000/user/hive/warehouse/db_hive.db atguigu USER

切換當前數據庫

hive (default)> use db_hive;

3. 修改數據庫

用戶可以使用alter database命令爲某個數據庫的DBPROPERTIES設置鍵-值對屬性值,來描述這個數據庫的屬性信息。數據庫的其他元數據信息都是不可更改的,包括數據庫名和數據庫所在的目錄位置。

hive (default)> alter database db_hive set dbproperties(‘createtime’=‘20170830’);

在hive中查看修改結果

hive> desc database extended db_hive;
db_name comment location owner_name owner_type parameters
db_hive hdfs://hadoop102:8020/user/hive/warehouse/db_hive.db atguigu USER {createtime=20170830}

4. 刪除數據庫
  1. 刪除空數據庫

hive>drop database db_hive2;

  1. 如果刪除的數據庫不存在,最好採用 if exists判斷數據庫是否存在

hive> drop database db_hive;
FAILED: SemanticException [Error 10072]: Database does not exist: db_hive
hive> drop database if exists db_hive2;

  1. 如果數據庫不爲空,可以採用cascade命令,強制刪除

hive> drop database db_hive;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. InvalidOperationException(message:Database db_hive is not empty. One or more tables exist.)
hive> drop database db_hive cascade;

5. 創建表

建表語法:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name 
[(col_name data_type [COMMENT col_comment], ...)] 
[COMMENT table_comment] 
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] 
[CLUSTERED BY (col_name, col_name, ...) 
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] 
[ROW FORMAT row_format] 
[STORED AS file_format] 
[LOCATION hdfs_path]

字段說明:
(1)CREATE TABLE 創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用戶可以用 IF NOT EXISTS 選項來忽略這個異常。
(2)EXTERNAL關鍵字可以讓用戶創建一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION),Hive創建內部表時,會將數據移動到數據倉庫指向的路徑;若創建外部表,僅記錄數據所在的路徑,不對數據的位置做任何改變。在刪除表的時候,內部表的元數據和數據會被一起刪除,而外部表只刪除元數據,不刪除數據
(3)COMMENT:爲表和列添加註釋。
(4)PARTITIONED BY創建分區表
(5)CLUSTERED BY創建分桶表
(6)SORTED BY 不常用
(7)ROW FORMAT
DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
| SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, …)]
用戶在建表的時候可以自定義SerDe或者使用自帶的SerDe。如果沒有指定ROW FORMAT 或者ROW FORMAT DELIMITED,將會使用自帶的SerDe。在建表的時候,用戶還需要爲表指定列,用戶在指定表的列的同時也會指定自定義的SerDe,Hive通過SerDe確定表的具體的列的數據。
SerDe是Serialize/Deserilize的簡稱,目的是用於序列化和反序列化。
(8)STORED AS指定存儲文件類型
常用的存儲文件類型:SEQUENCEFILE(二進制序列文件)、TEXTFILE(文本)、RCFILE(列式存儲格式文件)
如果文件數據是純文本,可以使用STORED AS TEXTFILE。如果數據需要壓縮,使用 STORED AS SEQUENCEFILE。
(9)LOCATION :指定表在HDFS上的存儲位置。
(10)LIKE允許用戶複製現有的表結構,但是不復制數據。

管理表(內部表)
  1. 理論
    默認創建的表都是所謂的管理表,有時也被稱爲內部表。因爲這種表,Hive會(或多或少地)控制着數據的生命週期。Hive默認情況下會將這些表的數據存儲在由配置項hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定義的目錄的子目錄下。當我們刪除一個管理表時,Hive也會刪除這個表中數據。管理表不適合和其他工具共享數據。
  2. 案例實操
    普通創建表
create table if not exists student2(
id int, name string
)
row format delimited fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/student2';

根據查詢結果創建表(查詢的結果會添加到新創建的表中)

create table if not exists student3 as select id, name from student;

  1. 根據已經存在的表結構創建表

create table if not exists student4 like student;

  1. 查詢表的類型

hive (default)> desc formatted student2;
Table Type: MANAGED_TABLE

外部表
  1. 理論
    因爲表是外部表,所以Hive並非認爲其完全擁有這份數據。刪除該表並不會刪除掉這份數據,不過描述表的元數據信息會被刪除掉。
  2. 管理表和外部表的使用場景
    每天將收集到的網站日誌定期流入HDFS文本文件。在外部表(原始日誌表)的基礎上做大量的統計分析,用到的中間表、結果表使用內部表存儲,數據通過SELECT+INSERT 進入內部表。
  3. 案例實操 分別創建部門和員工外部表,並向表中導入數據。
    原始數據
    dept
10	ACCOUNTING	1700
20	RESEARCH	1800
30	SALES	1900
40	OPERATIONS	1700

emp

7369	SMITH	CLERK	7902	1980-12-17	800.00		20
7499	ALLEN	SALESMAN	7698	1981-2-20	1600.00	300.00	30
7521	WARD	SALESMAN	7698	1981-2-22	1250.00	500.00	30
7566	JONES	MANAGER	7839	1981-4-2	2975.00		20
7654	MARTIN	SALESMAN	7698	1981-9-28	1250.00	1400.00	30
7698	BLAKE	MANAGER	7839	1981-5-1	2850.00		30
7782	CLARK	MANAGER	7839	1981-6-9	2450.00		10
7788	SCOTT	ANALYST	7566	1987-4-19	3000.00		20
7839	KING	PRESIDENT		1981-11-17	5000.00		10
7844	TURNER	SALESMAN	7698	1981-9-8	1500.00	0.00	30
7876	ADAMS	CLERK	7788	1987-5-23	1100.00		20
7900	JAMES	CLERK	7698	1981-12-3	950.00		30
7902	FORD	ANALYST	7566	1981-12-3	3000.00		20
7934	MILLER	CLERK	7782	1982-1-23	1300.00		10

創建部門表(外部)

create external table if not exists default.dept(
deptno int,
dname string,
loc int
)
row format delimited fields terminated by '\t';

創建員工表(外部)

create external table if not exists default.emp(
empno int,
ename string,
job string,
mgr int,
hiredate string, 
sal double, 
comm double,
deptno int)
row format delimited fields terminated by '\t';

查看創建的表

hive (default)> show tables;
OK
tab_name
dept
emp

向外部表中導入數據
導入數據

hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table default.dept;
hive (default)> load data local inpath ‘/opt/module/datas/emp.txt’ into table default.emp;

查詢結果

hive (default)> select * from emp;
hive (default)> select * from dept;

查看錶格式化數據

hive (default)> desc formatted dept;
Table Type: EXTERNAL_TABLE

管理表與外部表的互相轉換

查詢表的類型

hive (default)> desc formatted student2;
Table Type: MANAGED_TABLE

修改內部表student2爲外部表

alter table student2 set tblproperties('EXTERNAL'='TRUE');

查詢表的類型

hive (default)> desc formatted student2;
Table Type: EXTERNAL_TABLE

修改外部表student2爲內部表

alter table student2 set tblproperties('EXTERNAL'='FALSE');

查詢表的類型

hive (default)> desc formatted student2;
Table Type: MANAGED_TABLE

注意:(‘EXTERNAL’=‘TRUE’) 和 (‘EXTERNAL’=‘FALSE’)爲固定寫法,區分大小寫!

6. 分區表

分區表實際上就是對應一個HDFS文件系統上的獨立的文件夾,該文件夾下是該分區所有的數據文件。Hive中的分區就是分目錄,把一個大的數據集根據業務需要分割成小的數據集。在查詢時通過WHERE子句中的表達式選擇查詢所需要的指定的分區,這樣的查詢效率會提高很多。

hadoop fs -ls hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat
drwxrwxrwx - hadoop hadoop 0 2020-05-31 00:28 hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-05-30
drwxrwxrwx - hadoop hadoop 0 2020-06-01 00:30 hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-05-31
drwxrwxrwx - hadoop hadoop 0 2020-06-02 00:34 hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-06-01
注意: etl_date=2020-05-30 這是個HDFS文件系統中的文件夾哦!

hadoop fs -ls hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-06-01
-rwxrwxrwx 3 hadoop hadoop 3820 2020-06-02 00:34 hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-06-01/part-00000
-rwxrwxrwx 3 hadoop hadoop 8877055 2020-06-02 00:34 hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-06-01/part-00001
-rwxrwxrwx 3 hadoop hadoop 7491127 2020-06-02 00:34 hdfs://cluster/user/hive/warehouse/dp_ods.db/sowhat/etl_date=2020-06-01/part-00002

分區表基本操作

  1. 引入分區表(需要根據日期對日誌進行管理)

/user/hive/warehouse/log_partition/20170702/20170702.log
/user/hive/warehouse/log_partition/20170703/20170703.log
/user/hive/warehouse/log_partition/20170704/20170704.log

  1. 創建分區表語法

hive (default)> create table dept_partition(
deptno int, dname string, loc string
)
partitioned by (month string)
row format delimited fields terminated by ‘\t’;

  1. 加載數據到分區表中

hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table default.dept_partition partition(month='201709');
hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table default.dept_partition partition(month='201708');
hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table default.dept_partition partition(month='201707’);
hive (default)> insert overwrite table tempName partition(etl_date) select 字段 from otherTable where etl_date = ‘2020-06-05’;

在這裏插入圖片描述
在這裏插入圖片描述
4. 查詢分區表中數據
單分區查詢

hive (default)> select * from dept_partition where month='201709';

多分區聯合查詢

hive (default)> select * from dept_partition where month='201709'
              union
              select * from dept_partition where month='201708'
              union
              select * from dept_partition where month='201707';

_u3.deptno      _u3.dname       _u3.loc _u3.month
10      ACCOUNTING      NEW YORK        201707
10      ACCOUNTING      NEW YORK        201708
10      ACCOUNTING      NEW YORK        201709
20      RESEARCH        DALLAS  201707
20      RESEARCH        DALLAS  201708
20      RESEARCH        DALLAS  201709
30      SALES   CHICAGO 201707
30      SALES   CHICAGO 201708
30      SALES   CHICAGO 201709
40      OPERATIONS      BOSTON  201707
40      OPERATIONS      BOSTON  201708
40      OPERATIONS      BOSTON  201709
  1. 增加分區
    創建單個分區

hive (default)> alter table dept_partition add partition(month='201706') ;

同時創建多個分區

hive (default)> alter table dept_partition add partition(month='201705') partition(month='201704');

  1. 刪除分區
    刪除單個分區

hive (default)> alter table dept_partition drop partition (month='201704');

同時刪除多個分區

hive (default)> alter table dept_partition drop partition (month='201705'), partition (month='201706');

  1. 查看分區表有多少分區

hive> show partitions dept_partition;

  1. 查看分區表結構

hive> desc formatted dept_partition;

在這裏插入圖片描述

分區表注意事項

創建二級分區表

hive (default)> create table dept_partition2(
               deptno int, dname string, loc string
               )
               partitioned by (month string, day string)
               row format delimited fields terminated by '\t';

正常的加載數據
加載數據到二級分區表中

hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table
default.dept_partition2 partition(month='201709', day='13');

查詢分區數據

hive (default)> select * from dept_partition2 wheremonth='201709' and day='13';

把數據直接上傳到分區目錄上,讓分區表和數據產生關聯的三種方式
  1. 上傳數據後修復

hive (default)> dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=201709/day=12;
hive (default)> dfs -put /opt/module/datas/dept.txt /user/hive/warehouse/dept_partition2/month=201709/day=12;

查詢數據(查詢不到剛上傳的數據

hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘12’;

執行修復命令

hive> msck repair table dept_partition2;

再次查詢數據

hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘12’;

  1. 上傳數據後添加分區

hive (default)> dfs -mkdir -p
/user/hive/warehouse/dept_partition2/month=201709/day=11;
hive (default)> dfs -put /opt/module/datas/dept.txt /user/hive/warehouse/dept_partition2/month=201709/day=11;

執行添加分區

hive (default)> alter table dept_partition2 add partition(month='201709', day='11');

查詢數據

hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘11’;

  1. 創建文件夾後load數據到分區

hive (default)> dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=201709/day=10;

上傳數據

hive (default)> load data local inpath ‘/opt/module/datas/dept.txt’ into table
dept_partition2 partition(month='201709',day='10');

查詢數據

hive (default)> select * from dept_partition2 where month=‘201709’ and day=‘10’;

7. 修改表

重命名錶

ALTER TABLE table_name RENAME TO new_table_name

增加/修改/替換列信息
更新列

ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]

增加和替換列

ALTER TABLE table_nameADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], …)

注:ADD是代表新增一字段,字段位置在所有列後面(partition列前),REPLACE則是表示替換表中所有字段。

1)查詢表結構
hive> desc dept_partition;2)添加列
hive (default)> alter table dept_partition add columns(deptdesc string);3)查詢表結構
hive> desc dept_partition;4)更新列
hive (default)> alter table dept_partition change column deptdesc desc int;5)查詢表結構
hive> desc dept_partition;6)替換列
hive (default)> alter table dept_partition replace columns(deptno string, dname
 string, loc string);7)查詢表結構
hive> desc dept_partition;

刪除表

hive (default)> drop table dept_partition;

5. DML

適用範圍:對數據庫中的數據進行一些簡單操作,如insert,delete,update,select等.
DML操作是需要手動控制事務的開啓、提交(commit)和回滾的

數據導入

向表中裝載數據(Load)
1.語法

hive> load data [local] inpath ‘/opt/module/datas/student.txt’ overwrite | into table student [partition (partcol1=val1,…)];
(1)load data:表示加載數據
(2)local:表示從本地加載數據到hive表;否則從HDFS加載數據到hive表
(3)inpath:表示加載數據的路徑
(4)overwrite:表示覆蓋表中已有數據,否則表示追加
(5)into table:表示加載到哪張表
(6)student:表示具體的表
(7)partition:表示上傳到指定分區

實操案例
創建一張表

hive (default)> create table student(id string, name string) row format delimited fields terminated by ‘\t’;

  1. 加載本地文件到hive

hive (default)> load data local inpath ‘/opt/module/datas/student.txt’ into table default.student;

  1. 加載HDFS文件到hive中 上傳文件到HDFS

hive (default)> dfs -put /opt/module/datas/student.txt /user/atguigu/hive;

加載HDFS上數據

hive (default)> load data inpath ‘/user/atguigu/hive/student.txt’ into table default.student;

  1. 加載數據覆蓋表中已有的數據
    上傳文件到HDFS

hive (default)> dfs -put /opt/module/datas/student.txt /user/atguigu/hive;

加載數據覆蓋表中已有的數據

hive (default)> load data inpath ‘/user/atguigu/hive/student.txt’ overwrite table default.student;

通過查詢語句向表中插入數據(Insert)
  1. 創建一張分區表

hive (default)> create table student(id int, name string) partitioned by (month string) row format delimited fields terminated by ‘\t’;

  1. 基本插入數據

hive (default)> insert into table student partition(month=‘201709’) values(1,‘wangwu’);

  1. 基本模式插入(根據單張表查詢結果)

hive (default)> insert overwrite table student partition(month=‘201708’) select id, name from student where month=‘201709’;

  1. 多插入模式(根據多張表查詢結果)

hive (default)> from student
insert overwrite table student partition(month=‘201707’)
select id, name where month=‘201709’
insert overwrite table student partition(month=‘201706’)
select id, name where month=‘201709’;

查詢語句中創建表並加載數據(As Select)
  1. 根據查詢結果創建表(查詢的結果會添加到新創建的表中)

create table if not exists student3 as select id, name from student;

創建表時通過Location指定加載數據路徑
  1. 創建表,並指定在hdfs上的位置

hive (default)> create table if not exists student5(id int, name string ) row format delimited fields terminated by ‘\t’ location ‘/user/hive/warehouse/student5’;

  1. 上傳數據到hdfs上

hive (default)> dfs -put /opt/module/datas/student.txt /user/hive/warehouse/student5;

  1. 查詢數據

hive (default)> select * from student5;

Import數據到指定Hive表中

注意:先用export導出後,再將數據導入( 只能是個空表數據導入)。

hive (default)> import table student2 partition(month=‘201709’) from
‘/user/hive/warehouse/export/student’;

數據導出

Insert導出
  1. 將查詢的結果導出到本地

hive (default)> insert overwrite local directory ‘/opt/module/datas/export/student’ select * from student;

  1. 將查詢的結果格式化導出到本地
  1. hive(default)>insert overwrite local directory ‘/opt/module/datas/export/student1’ ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’ select * from student;
  2. INSERT OVERWRITE LOCAL DIRECTORY ‘pwd’
    ROW FORMAT SERDE ‘org.apache.hadoop.hive.serde2.OpenCSVSerde’
    WITH SERDEPROPERTIES (
    “separatorChar” = “,”,
    “quoteChar” = “’”,
    “escapeChar” = “\”
    )
    STORED AS TEXTFILE
    select * from table ;
  1. 將查詢的結果導出到HDFS上(沒有local)
  1. insert overwrite directory ‘/user/atguigu/student2’ ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’ select * from student;
Hadoop命令導出到本地

hive (default)> dfs -get /user/hive/warehouse/student/month=201709/000000_0
/opt/module/datas/export/student3.txt;

Hive Shell 命令導出

基本語法:(hive -f/-e 執行語句或者腳本 > file)

[atguigu@hadoop102 hive]$ bin/hive -e ‘select * from default.student;’ >
/opt/module/datas/export/student4.txt;

Export導出到HDFS上

在HDFS上 元數據跟 HDFS數據都 複製了一份,用import 的時候一定要是個新表 並且數據字段要匹配。
(defahiveult)> export table default.student to ‘/user/hive/warehouse/export/student’;

清除表中數據(Truncate)

注意:truncate只能刪除管理表(刪除的是HDFS),不能刪除外部表中數據

hive (default)> truncate table student;

6. 查詢

查詢語句語法:

[WITH CommonTableExpression (, CommonTableExpression)*]    (Note: Only available
 starting with Hive 0.13.0)
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 number]
基本查詢(Select…From)
  1. 全表查詢

hive (default)> select * from emp;

  1. 選擇特定列查詢

hive (default)> select empno, ename from emp;

注意

(1)SQL 語言大小寫不敏感。
(2)SQL 可以寫在一行或者多行
(3)關鍵字不能被縮寫也不能分行
(4)各子句一般要分行寫。
(5)使用縮進提高語句的可讀性。

列別名
  1. 重命名一個列
  2. 便於計算
  3. 緊跟列名,也可以在列名和別名之間加入關鍵字‘AS’
  4. 案例實操
    查詢名稱和部門

hive (default)> select ename AS name, deptno dn from emp;

算數運算符
運算符 描述
A+B A和B 相加
A-B A減去B
A*B A和B 相乘
A/B A除以B
A%B A對B取餘
A&B A和B按位取與
A B
A^B A和B按位取異或
~A A按位取反

查詢出所有員工的薪水後加1顯示。

hive (default)> select sal +1 from emp;

常用函數

  1. 求總行數(count)

hive (default)> select count(*) cnt from emp;

  1. 求工資的最大值(max)

hive (default)> select max(sal) max_sal from emp;

  1. 求工資的最小值(min)

hive (default)> select min(sal) min_sal from emp;

  1. 求工資的總和(sum)

hive (default)> select sum(sal) sum_sal from emp;

  1. 求工資的平均值(avg)

hive (default)> select avg(sal) avg_sal from emp;

  1. 需求查詢後的數據按照自增ID類似的排序,然後每個table基數

insert overwrite table selftableName
select
(row_number() over(partition by 1) -1)|(1*4294967296) as global_id,
a.id from sowhat;

  1. Limit語句
    典型的查詢會返回多行數據。LIMIT子句用於限制返回的行數。

hive (default)> select * from emp limit 5;

  1. Where語句

1.使用WHERE子句,將不滿足條件的行過濾掉
2.WHERE子句緊隨FROM子句
3.案例實操
查詢出薪水大於1000的所有員工
hive (default)> select * from emp where sal >1000;

比較運算符(Between/In/ Is Null)

下面表中描述了謂詞操作符,這些操作符同樣可以用於JOIN…ON和HAVING語句中。

操作符 支持的數據類型 描述
A=B 基本數據類型 如果A等於B則返回TRUE,反之返回FALSE, null = null 結果是NULL
A<=>B 基本數據類型(大部分情況跟 = 類似) null = null,則返回TRUE,其他的和等號(=)操作符的結果一致,如果任一爲NULL則結果爲NULL
A<>B, A!=B 基本數據類型 A或者B爲NULL則返回NULL;如果A不等於B,則返回TRUE,反之返回FALSE
A<B 基本數據類型 A或者B爲NULL,則返回NULL;如果A小於B,則返回TRUE,反之返回FALSE
A<=B 基本數據類型 A或者B爲NULL,則返回NULL;如果A小於等於B,則返回TRUE,反之返回FALSE
A>B 基本數據類型 A或者B爲NULL,則返回NULL;如果A大於B,則返回TRUE,反之返回FALSE
A>=B 基本數據類型 A或者B爲NULL,則返回NULL;如果A大於等於B,則返回TRUE,反之返回FALSE
A [NOT] BETWEEN B AND C 基本數據類型 如果A,B或者C任一爲NULL,則結果爲NULL。如果A的值大於等於B而且小於或等於C,則結果爲TRUE,反之爲FALSE。如果使用NOT關鍵字則可達到相反的效果。
A IS NULL 所有數據類型 如果A等於NULL,則返回TRUE,反之返回FALSE
A IS NOT NULL 所有數據類型 如果A不等於NULL,則返回TRUE,反之返回FALSE
IN(數值1, 數值2) 所有數據類型 使用 IN運算顯示列表中的值
A [NOT] LIKE B STRING 類型 B是一個SQL下的簡單正則表達式,如果A與其匹配的話,則返回TRUE;反之返回FALSE。B的表達式說明如下:‘x%’表示A必須以字母‘x’開頭,‘%x’表示A必須以字母’x’結尾,而‘%x%’表示A包含有字母’x’,可以位於開頭,結尾或者字符串中間。如果使用NOT關鍵字則可達到相反的效果。
A RLIKE B, A REGEXP B STRING 類型 B是一個正則表達式,如果A與其匹配,則返回TRUE;反之返回FALSE。匹配使用的是JDK中的正則表達式接口實現的,因爲正則也依據其中的規則。例如,正則表達式必須和整個字符串A相匹配,而不是隻需與其字符串匹配。

案例實操

  1. 查詢出薪水等於5000的所有員工

hive (default)> select * from emp where sal =5000;

  1. 查詢工資在500到1000的員工信息

hive (default)> select * from emp where sal between 500 and 1000;

  1. 查詢comm爲空的所有員工信息

hive (default)> select * from emp where comm is null;

  1. 查詢工資是1500或5000的員工信息

hive (default)> select * from emp where sal IN (1500, 5000);

Like和RLike

1)使用LIKE運算選擇類似的值
2)選擇條件可以包含字符或數字:

% 代表零個或多個字符(任意個字符)。
_ 代表一個字符。

3)RLIKE子句是Hive中這個功能的一個擴展,其可以通過Java的正則表達式這個更強大的語言來指定匹配條件。
4)案例實操
(1)查找以2開頭薪水的員工信息
hive (default)> select * from emp where sal LIKE ‘2%’;
(2)查找第二個數值爲2的薪水的員工信息
hive (default)> select * from emp where sal LIKE ‘_2%’;
(3)查找薪水中含有2的員工信息
hive (default)> select * from emp where sal RLIKE ‘[2]’;

邏輯運算符(And/Or/Not)
操作符 含義
AND 邏輯並
OR 邏輯或
NOT 邏輯否
  1. 查詢薪水大於1000,部門是30

hive (default)> select * from emp where sal>1000 and deptno=30;

  1. 查詢薪水大於1000,或者部門是30

hive (default)> select * from emp where sal>1000 or deptno=30;

  1. 查詢除了20部門和30部門以外的員工信息

hive (default)> select * from emp where deptno not IN(30, 20);

分組

Group By語句
GROUP BY語句通常會和聚合函數一起使用,按照一個或者多個列隊結果進行分組,然後對每個組執行聚合操作。
案例實操:

  1. 計算emp表每個部門的平均工資

hive (default)> select t.deptno, avg(t.sal) avg_sal from emp t group by t.deptno;

  1. 計算emp每個部門中每個崗位的最高薪水

hive (default)> select t.deptno, t.job, max(t.sal) max_sal from emp t group by
t.deptno, t.job;

Having語句

  1. having與where不同點
    (1)where針對表中的列發揮作用,查詢數據;having針對查詢結果中的列發揮作用,篩選數據。
    (2)where後面不能寫分組函數,而having後面可以使用分組函數
    (3)having 只用於 group by分組統計語句。
  2. 案例實操
    求每個部門的平均薪水大於2000的部門
    求每個部門的平均工資

hive (default)> select deptno, avg(sal) from emp group by deptno;

求每個部門的平均薪水大於2000的部門

hive (default)> select deptno, avg(sal) avg_sal from emp group by deptno having avg_sal > 2000;

Join

Hive支持通常的SQL JOIN 語句,但是只支持等值連接不支持非等值連接
表的別名

  1. 好處

(1)使用別名可以簡化查詢。
(2)使用表名前綴可以提高執行效率。

  1. 案例實操
    合併員工表和部門表

hive (default)> select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
= d.deptno;

內連接
內連接:只有進行連接的兩個表中都存在與連接條件相匹配的數據纔會被保留下來。

hive (default)> select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
= d.deptno;

左外連接
左外連接:JOIN操作符左邊表中符合WHERE子句的所有記錄將會被返回。

hive (default)> select e.empno, e.ename, d.deptno from emp eleft join dept d on e.deptno = d.deptno;

右外連接
右外連接:JOIN操作符右邊表中符合WHERE子句的所有記錄將會被返回。

hive (default)> select e.empno, e.ename, d.deptno from emp e right join dept d on e.deptno
= d.deptno;

滿外連接
滿外連接:將會返回所有表中符合WHERE語句條件的所有記錄。如果任一表的指定字段沒有符合條件的值的話,那麼就使用NULL值替代

hive (default)> select e.empno, e.ename, d.deptno from emp e full join dept d on e.deptno
= d.deptno;

多表連接
注意:連接 n個表,至少需要n-1個連接條件。例如:連接三個表,至少需要兩個連接條件。

hive (default)>SELECT e.ename, d.deptno, l. loc_name
FROM   emp e 
JOIN   dept d
ON     d.deptno = e.deptno 
JOIN   location l
ON     d.loc = l.loc;

大多數情況下,Hive會對每對JOIN連接對象啓動一個MapReduce任務。本例中會首先啓動一個MapReduce job對錶e和表d進行連接操作,然後會再啓動一個MapReduce job將第一個MapReduce job的輸出和表l;進行連接操作。
注意:爲什麼不是表d和表l先進行連接操作呢?這是因爲Hive總是按照從左到右的順序執行的

笛卡爾積
笛卡爾積就是 m*n行哦一般。

  1. 笛卡爾集會在下面條件下產生

(1)省略連接條件
(2)連接條件無效
(3)所有表中的所有行互相連接

  1. 案例實操

hive (default)> select empno, dname from emp, dept;

連接謂詞中不支持or

hive (default)> select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
= d.deptno or e.ename=d.ename; 錯誤的

排序

全局排序Order By
Order By:全局排序一個Reducer

  1. 使用 ORDER BY 子句排序

ASC(ascend): 升序(默認)
DESC(descend): 降序

  1. ORDER BY 子句在SELECT語句的結尾
  2. 案例實操

查詢員工信息按工資升序排列
hive (default)> select * from emp order by sal;
查詢員工信息按工資降序排列
hive (default)> select * from emp order by sal desc;

按照別名排序–按照員工薪水的2倍排序

hive (default)> select ename, sal*2 twosal from emp order by twosal;

多個列排序

按照部門和工資升序排序
hive (default)> select ename, deptno, sal from emp order by deptno, sal ;

每個MapReduce內部排序(Sort By
Sort By:每個Reducer內部進行排序,對全局結果集來說不是排序。

  1. 設置reduce個數

hive (default)> set mapreduce.job.reduces=3; 因爲沒有指定分區Hash值字段所以是隨機分區的。

  1. 查看設置reduce個數

hive (default)> set mapreduce.job.reduces;

  1. 根據部門編號降序查看員工信息

hive (default)> select * from emp sort by empno desc; 看不出來結果的

  1. 將查詢結果導入到文件中(按照部門編號降序排序)

hive (default)> insert overwrite local directory ‘/opt/module/datas/sortby-result’ select * from emp sort by deptno desc; 有三個reduce 文件
hive (default)> insert overwrite local directory ‘/opt/module/datas/orderby-result’ select * from emp order by deptno desc; 有一個reduce文件

分區排序(Distribute By)
Distribute By:類似MR 中 partition,進行分區,結合sort by使用。
注意:Hive要求Distribute By語句要寫在sort by語句之前。
對於distribute by進行測試,一定要分配多reduce進行處理,否則無法看到distribute by的效果。
案例實操:
(1)先按照部門編號分區(數據的Hash值),再按照員工編號降序排序。

hive (default)> set mapreduce.job.reduces=3;
hive (default)> insert overwrite local directory ‘/opt/module/datas/distribute-result’ select * from emp distribute by deptno sort by empno desc;

Cluster By
distribute bysorts by 字段相同時,可以使用cluster by方式。
cluster by除了具有distribute by的功能外還兼具sort by的功能。但是排序只能是升序排序,不能指定排序規則爲ASC或者DESC。
以下兩種寫法等價

hive (default)> select * from emp cluster by deptno;
hive (default)> select * from emp distribute by deptno sort by deptno;

注意:按照部門編號分區,不一定就是固定死的數值,可以是20號和30號部門分到一個分區裏面去。

排序總結
方法 解釋
order by 全局排序 reduce個數爲 一個。
sort by 此時一般reduce有多個,按照隨機的原則將數據放入到不同reduce中
distribute by 一般跟 sort by 聯用, distribute by 分區字段 sort by 排序字段 desc或者asc
cluster by 當 distribute by` 和 sorts by 字段相同時,可以使用cluster by方式。cluster by除了具有distribute by的功能外還兼
分桶及抽樣查詢

分區針對的是數據的存儲路徑(多加幾個文件夾);分桶針對的是數據文件(同一個文件夾內將文件分成多份)。
分區提供一個隔離數據和優化查詢的便利方式。不過,並非所有的數據集都可形成合理的分區,特別是之前所提到過的要確定合適的劃分大小這個疑慮。分桶是將數據集分解成更容易管理的若干部分的另一個技術。

  1. 數據準備:
1001	ss1
1002	ss2
1003	ss3
1004	ss4
1005	ss5
1006	ss6
1007	ss7
1008	ss8
1009	ss9
1010	ss10
1011	ss11
1012	ss12
1013	ss13
1014	ss14
1015	ss15
1016	ss16
  1. 創建分桶表
    類似MR中的 reduce 有 N個buckets, 分桶用的是table帶的字段,分區partition是單獨的字段。
create table stu_buck(id int, name string)
clustered by(id) 
into 4 buckets
row format delimited fields terminated by '\t';
  1. 查看錶結構

hive (default)> desc formatted stu_buck;
Num Buckets: 4

  1. 導入數據到分桶表中

hive (default)> load data local inpath ‘/opt/module/datas/student.txt’ into table stu_buck;

  1. 查看創建的分桶表中是否分成4個桶

    發現並沒有分成4個桶。是什麼原因呢? load 底層指令是用的Hadoop中的put方法放置的數據 !

創建分桶表時,數據通過子查詢的方式導入
6. 先建一個普通的stu表

create table stu(id int, name string) row format delimited fields terminated by ‘\t’;

  1. 向普通的stu表中導入數據

load data local inpath ‘/opt/module/datas/student.txt’ into table stu;

  1. 清空stu_buck表中數據

truncate table stu_buck; select * from stu_buck;

  1. 導入數據到分桶表,通過子查詢的方式

insert into table stu_buck select id, name from stu;

  1. 發現還是隻有一個分桶
    在這裏插入圖片描述
  2. 需要設置一個屬性

hive (default)> set hive.enforce.bucketing=true; 開啓分桶
hive (default)> set mapreduce.job.reduces=-1;讓系統根據桶的個數 實現reduce個數
hive (default)> truncate table stu_buck
hive (default)> insert into table stu_buck select id, name from stu;

在這裏插入圖片描述
12. 查詢分桶的數據

將數據按照id放到不同的桶裏,然後逐個顯示桶的數據
hive (default)> select * from stu_buck;
stu_buck.id stu_buck.name
1004 ss4
1008 ss8
1012 ss12
1016 ss16
1001 ss1
1005 ss5
1009 ss9
1013 ss13
1002 ss2
1006 ss6
1010 ss10
1014 ss14
1003 ss3
1007 ss7
1011 ss11
1015 ss15

分桶抽樣查詢

對於非常大的數據集,有時用戶需要使用的是一個具有代表性的查詢結果而不是全部結果。Hive可以通過對錶進行抽樣來滿足這個需求。查詢表stu_buck中的數據。

hive (default)> select * from stu_buck tablesample(bucket 1 out of 4 on id);

tablesample是抽樣語句,語法:TABLESAMPLE(BUCKET x OUT OF y) 。

y必須是table總bucket數的倍數或者因子。hive根據y的大小,決定抽樣的比例。例如,table總共分了4份,當y=2時,抽取(4/2=)2個bucket的數據,當y=8時,抽取(4/8=)1/2個bucket的數據。

x表示從哪個bucket開始抽取,如果需要取多個分區,以後的分區號爲當前分區號加上y。例如,table總bucket數爲4,tablesample(bucket 1 out of 2),表示總共抽取(4/2=)2個bucket的數據,抽取第1(x)個和第3(x+y)個bucket的數據。

Table被分成 16份,x= 1 y=4,則取的桶爲[1,5,9,13]
注意:x的值必須小於等於y的值,否則保持
證明:

table總數爲z,tablesample(bucket x out of y on id)。則最後一份桶索引是 x +(z/y - 1) *y = x-y+z
如果 x-y > 0 最後一份索引超出最大值了。

常用查詢函數

空字段賦值

  1. 函數說明

NVL:給值爲NULL的數據賦值,它的格式是NVL( string1, replace_with)。它的功能是如果string1爲NULL,則NVL函數返回replace_with的值,否則返回string1的值,如果兩個參數都爲NULL ,則返回NULL。

demo:

hive (default)> select nvl(comm,-1) from emp;
_c0
20.0
查找員工領導,而領導是沒有領導的
hive (default)> select nvl(leaderID,selfID) from emp;

時間類

  1. date_format:格式化時間 只認識-

select date_format(‘2019-06-29’,‘yyyy-MM-dd’);
2019-06-29

  1. date_add:時間跟天數相加

select date_add(‘2019-06-29’,5);
2019-07-04
select date_add(‘2019-06-29’,-5);
2019-06-24

  1. date_sub:時間跟天數相減

select date_sub(‘2019-06-29’,5);
2019-06-24
select date_sub(‘2019-06-29’,-5);
2019-07-04

  1. datediff:兩個時間日期相減(前面 減 後面)

select datediff(’ 2019-07-04’,‘2019-06-29’);
5

  1. date_format 只認識-

select date_format(‘2019/06/29’,‘yyyy-MM-dd’);
NULL
select regexp_replace(‘2019/06/29’,’/’,’-’);
2019-06-29

CASE WHEN
創建數據 導入數據,統計每個部門中男女數量

create table emp_sex(
name string, 
dept_id string, 
sex string) 
row format delimited fields terminated by "\t";

load data local inpath '/opt/module/datas/emp_sex.txt' into table emp_sex;

select 
  dept_id,
  sum(case sex when '男' then 1 else 0 end) male_count,
  sum(case sex when '女' then 1 else 0 end) female_count
from 
  emp_sex
group by
  dept_id;

select
   dept_id,
   sum(if(sex='男'10)) male_count,
   sum(if(sex='女'10)) female_count,
from emp_sex group by  dept_id;
行轉列
  1. CONCAT(string A/col, string B/col…):

返回輸入字符串連接後的結果,支持任意個輸入字符串;

  1. CONCAT_WS(separator, str1, str2,…):

它是一個特殊形式的 CONCAT()。第一個參數剩餘參數間的分隔符。分隔符可以是與剩餘參數一樣的字符串。如果分隔符是 NULL,返回值也將爲 NULL。這個函數會跳過分隔符參數後的任何 NULL 和空字符串。分隔符將被加到被連接的字符串之間;

  1. COLLECT_SET(col):

函數只接受基本數據類型,它的主要作用是將某字段的值進行去重彙總,產生array類型字段。多行彙總成一個array類型。

需求: 一個表有 姓名,血型,星座 三個字段。將血型跟星座一樣人彙總起來。

create table person_info(
name string, 
constellation string, 
blood_type string) 
row format delimited fields terminated by "\t";

load data local inpath “/opt/module/datas/person_info.txt” into table person_info;

select
    t1.base,
    concat_ws('|', collect_set(t1.name)) name
from
    (select name, concat(constellation, ",", blood_type) base from person_info) t1
group by
    t1.base;
列轉行
  1. EXPLODE(col):

將hive一列中複雜的array或者map結構拆分成多行。

  1. LATERAL VIEW

用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解釋:用於和split, explode等UDTF一起使用,它能夠將一列數據拆成多行數據,在此基礎上可以對拆分後的數據進行聚合。

  1. demo
    在這裏插入圖片描述
《疑犯追蹤》      懸疑
《疑犯追蹤》      動作
《疑犯追蹤》      科幻
《疑犯追蹤》      劇情
《Lie to me》   懸疑
《Lie to me》   警匪
《Lie to me》   動作
《Lie to me》   心理
《Lie to me》   劇情
《戰狼2》        戰爭
《戰狼2》        動作
《戰狼2》        災難
create table movie_info(
    movie string, 
    category array<string>) 
row format delimited fields terminated by "\t"
collection items terminated by ",";

load data local inpath "/opt/module/datas/movie.txt" into table movie_info;

select
    movie,
    category_name
from 
    movie_info lateral view explode(category) table_tmp as category_name;
窗口函數(重點)

我們都知道在sql中有一類函數叫做聚合函數,例如sum()、avg()、max()等等,這類函數可以將多行數據按照規則聚集爲一行,一般來講聚集後的行數是要少於聚集前的行數的.但是有時我們想要既顯示聚集前的數據,又要顯示聚集後的數據,這時我們便引入了窗口函數.

在深入研究over字句之前,一定要注意:在SQL處理中,窗口函數都是最後一步執行,而且僅位於Order by字句之前.

  1. 數據準備
name,orderdate,cost
jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94
  1. 建表 導數據
create table business(
name string, 
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

load data local inpath "/opt/module/datas/business.txt" into table business;
  1. 用法:

相關函數說明
OVER():指定分析函數工作的數據窗口大小,這個數據窗口大小可能會隨着行的變而變化
CURRENT ROW:當前行
n PRECEDING:往前 n 行數據
n FOLLOWING:往後 n 行數據
UNBOUNDED:起點,UNBOUNDED PRECEDING 表示從前面的起點, UNBOUNDED FOLLOWING表示到後面的終點
上面寫over裏面 下面寫over 前面
LAG(col,n):往前 n 行數據
LEAD(col,n):往後 n 行數據
NTILE(n):把有序分區中的行分發到指定數據的組中,各個組有編號,編號從1開始,對於每一行,NTILE 返回此行所屬的組的編號。注意:n必須爲int類型。

  1. 需求
    (1) 查詢在2017年4月份購買過的顧客及總人數
select name,count(*) over() from business where 
substring(orderdate,1,7) = '2017-04' group by name;
結果:
mart	2
jack	2

解釋:首先按照name分組排序顯示出中間結果,然後 count() over() 就是作用在這個中間結果上,進行count() 統計人名個數最終顯示

(2) 查詢顧客的購買明細及月購買總額

select name,orderdate,cost,sum(cost) over(partition by month(orderdate)) 
from business; 
解釋:按照月劃分數據  然後統計這個月的cost總和
jack	2017-01-01	10	205
jack	2017-01-08	55	205
tony	2017-01-07	50	205
jack	2017-01-05	46	205
tony	2017-01-04	29	205
tony	2017-01-02	15	205
jack	2017-02-03	23	23
mart	2017-04-13	94	341
jack	2017-04-06	42	341
mart	2017-04-11	75	341
mart	2017-04-09	68	341
mart	2017-04-08	62	341
neil	2017-05-10	12	12
neil	2017-06-12	80	80

(4)查看顧客上次的購買時間

select name,orderdate,cost, 
lag(orderdate,1,'defaulttime') over(partition by name order by orderdate ) as time1, lag(orderdate,2,'defaulttime') over (partition by name order by orderdate) as time2 
from business;


姓名	        日期	    價格  前一天日期	 前兩天日期
jack	2017-01-01	10	defaulttime	defaulttime
jack	2017-01-05	46	2017-01-01	defaulttime
jack	2017-01-08	55	2017-01-05	2017-01-01
jack	2017-02-03	23	2017-01-08	2017-01-05
jack	2017-04-06	42	2017-02-03	2017-01-08
mart	2017-04-08	62	defaulttime	defaulttime
mart	2017-04-09	68	2017-04-08	defaulttime
mart	2017-04-11	75	2017-04-09	2017-04-08
mart	2017-04-13	94	2017-04-11	2017-04-09
neil	2017-05-10	12	defaulttime	defaulttime
neil	2017-06-12	80	2017-05-10	defaulttime
tony	2017-01-02	15	defaulttime	defaulttime
tony	2017-01-04	29	2017-01-02	defaulttime
tony	2017-01-07	50	2017-01-04	2017-01-02

(5)查詢前20%時間的訂單信息

select * from (
    select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
    from business
) t
where sorted = 1;

jack	2017-01-01	10	1
tony	2017-01-02	15	1
tony	2017-01-04	29	1
jack	2017-01-05	46	2
tony	2017-01-07	50	2
jack	2017-01-08	55	2
jack	2017-02-03	23	3
jack	2017-04-06	42	3
mart	2017-04-08	62	3
mart	2017-04-09	68	4
mart	2017-04-11	75	4
mart	2017-04-13	94	4
neil	2017-05-10	12	5
neil	2017-06-12	80	5
開窗函數demo

以下實驗均關注最後一列

  1. 所有行相加
select name,orderdate,cost,sum(cost) over() as sample1 from business; 
mart	2017-04-13	94	661
neil	2017-06-12	80	661
mart	2017-04-11	75	661
neil	2017-05-10	12	661
mart	2017-04-09	68	661
  1. 按name分組,組內數據相加
select name,orderdate,cost,sum(cost) over(partition by name) as sample2
 from business;

jack	2017-01-05	46	176
jack	2017-01-08	55	176
jack	2017-01-01	10	176
jack	2017-04-06	42	176
jack	2017-02-03	23	176
mart	2017-04-13	94	299
mart	2017-04-11	75	299
mart	2017-04-09	68	299
mart	2017-04-08	62	299
neil	2017-05-10	12	92
neil	2017-06-12	80	92
tony	2017-01-04	29	94
tony	2017-01-02	15	94
tony	2017-01-07	50	94
  1. 按name分組,組內數據累加
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate) as sample3
 from business; 
跟下面類似
select name,orderdate,cost,
sum(cost) over(distribute by name sort by orderdate) as sample3 
from business; 
jack	2017-01-01	10	10
jack	2017-01-05	46	56
jack	2017-01-08	55	111
jack	2017-02-03	23	134
jack	2017-04-06	42	176
...
  1. 和sample3一樣,由起點到當前行的聚合
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
 between UNBOUNDED PRECEDING and current row ) as sample4 
 from business; 
jack	2017-01-01	10	10
jack	2017-01-05	46	56
jack	2017-01-08	55	111
jack	2017-02-03	23	134
jack	2017-04-06	42	176
...
  1. 當前行和前面一行做聚合
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows 
between 1 PRECEDING and current row) as sample5 
from business; 
jack	2017-01-01	10	10
jack	2017-01-05	46	56 = 46 + 10
jack	2017-01-08	55	101 = 44 + 46
jack	2017-02-03	23	78  = 23 + 55
jack	2017-04-06	42	65  = 42 + 23
mart	2017-04-08	62	62 
mart	2017-04-09	68	130
mart	2017-04-11	75	143
mart	2017-04-13	94	169
neil	2017-05-10	12	12
neil	2017-06-12	80	92
tony	2017-01-02	15	15
tony	2017-01-04	29	44
tony	2017-01-07	50	79
  1. 當前行和前邊一行及後面一行
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
 between 1 PRECEDING AND 1 FOLLOWING ) as sample6
from business; 
jack	2017-01-01	10	56  = 10 + 46
jack	2017-01-05	46	111 = 46 + 10 + 55
jack	2017-01-08	55	124 = 55 + 46 + 23
jack	2017-02-03	23	120 = 23 + 55 + 42
jack	2017-04-06	42	65  = 42 + 23
mart	2017-04-08	62	130
mart	2017-04-09	68	205
mart	2017-04-11	75	237
mart	2017-04-13	94	169
neil	2017-05-10	12	92
neil	2017-06-12	80	92
tony	2017-01-02	15	44
tony	2017-01-04	29	94
tony	2017-01-07	50	79
  1. 當前行及後面所有行
select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 from business; 
jack	2017-01-01	10	176 = 10 + 46 + 55 + 23 + 42
jack	2017-01-05	46	166 = 46 + 55 + 23 + 42
jack	2017-01-08	55	120 = 55 + 23 + 42
jack	2017-02-03	23	65  =  23 + 42
jack	2017-04-06	42	42  =  42
mart	2017-04-08	62	299
mart	2017-04-09	68	237
mart	2017-04-11	75	169
mart	2017-04-13	94	94
neil	2017-05-10	12	92
neil	2017-06-12	80	80
tony	2017-01-02	15	94
tony	2017-01-04	29	79
tony	2017-01-07	50	50

Rank
函數說明

rank():排序相同時會重複,總數不會變
dense_rank():排序相同時會重複,總數會減少
row_number():會根據順序計算

demo:

select name,subject,score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from score;

name    subject score   rp      drp     rmp
孫悟空  數學    95      1       1       1
宋宋    數學    86      2       2       2
婷婷    數學    85      3       3       3
大海    數學    56      4       4       4
宋宋    英語    84      1       1       1
大海    英語    84      1       1       2
婷婷    英語    78      3(跳過22       3
孫悟空  英語    68      4       3(總數少) 4
大海    語文    94      1       1       1
孫悟空  語文    87      2       2       2
婷婷    語文    65      3       3       3
宋宋    語文    64      4       4       4

7. 函數

系統內置函數
  1. 查看系統自帶的函數

hive> show functions;

  1. 顯示自帶的函數的用法

hive> desc function upper;

  1. 詳細顯示自帶的函數的用法

hive> desc function extended upper;

自定義函數
  1. Hive 自帶了一些函數,比如:max/min等,但是數量有限,自己可以通過自定義UDF來方便的擴展。
  2. 當Hive提供的內置函數無法滿足你的業務處理需要時,此時就可以考慮使用用戶自定義函數(UDF:user defined function)。
  3. 根據用戶自定義函數類別分爲以下三種(看行):
  1. UDF(User-Defined-Function)

一進一出
類似:upper,trim

  1. UDAF(User-Defined Aggregation Function)

聚集函數,多進一出
類似於:count/max/min
樣例:demo

  1. UDTF(User-Defined Table-Generating Functions)

一進多出
如:lateral view explore()
樣例:demo

UDF步驟

  1. 繼承org.apache.hadoop.hive.ql.UDF
  2. 需要實現evaluate函數;evaluate函數支持重載;
  3. 在hive的命令行窗口創建函數

add jar linux_jar_path
create [temporary] function [dbname.]function_name AS com.sowhat.demo.ClassName;
Temporary:臨時的,當前hive窗口關閉 函數就消失
添加的函數是不能跨庫的

  1. 在hive的命令行窗口刪除函數

drop [temporary] function [if exists] [dbname.]function_name;

8. 壓縮跟存儲

Hadoop源碼編譯支持Snappy壓縮
  1. 資源準備

CentOS聯網
配置CentOS能連接外網。Linux虛擬機ping www.baidu.com 是暢通的
注意:採用root角色編譯,減少文件夾權限出現問題
jar包準備(hadoop源碼、JDK8 、maven、protobuf)
(1)hadoop-2.7.2-src.tar.gz
(2)jdk-8u144-linux-x64.tar.gz
(3)snappy-1.1.3.tar.gz
(4)apache-maven-3.0.5-bin.tar.gz
(5)protobuf-2.5.0.tar.gz

  1. jar包安裝

注意:所有操作必須在root用戶下完成

  1. JDK解壓、配置環境變量JAVA_HOME和PATH,驗證java-version(如下都需要驗證是否配置成功)
    [root@hadoop101 software] # tar -zxf jdk-8u144-linux-x64.tar.gz -C /opt/module/
    [root@hadoop101 software]# vi /etc/profile
    export JAVA_HOME=/opt/module/jdk1.8.0_144
    export PATH=PATH:PATH:JAVA_HOME/bin
    [root@hadoop101 software]#source /etc/profile
    驗證命令:java -version
  2. Maven解壓、配置 MAVEN_HOME和PATH
    [root@hadoop101 software]# tar -zxvf apache-maven-3.0.5-bin.tar.gz -C /opt/module/
    [root@hadoop101 apache-maven-3.0.5]# vi /etc/profile
    export MAVEN_HOME=/opt/module/apache-maven-3.0.5
    export PATH=PATH:PATH:MAVEN_HOME/bin
    [root@hadoop101 software]#source /etc/profile
    驗證命令:mvn -version
  1. 編譯源碼
  1. 準備編譯環境
    [root@hadoop101 software]# yum install svn
    [root@hadoop101 software]# yum install autoconf automake libtool cmake
    [root@hadoop101 software]# yum install ncurses-devel
    [root@hadoop101 software]# yum install openssl-devel
    [root@hadoop101 software]# yum install gcc*
  2. 編譯安裝snappy
    [root@hadoop101 software]# tar -zxvf snappy-1.1.3.tar.gz -C /opt/module/
    [root@hadoop101 module]# cd snappy-1.1.3/
    [root@hadoop101 snappy-1.1.3]# ./configure
    [root@hadoop101 snappy-1.1.3]# make
    [root@hadoop101 snappy-1.1.3]# make install
  3. 查看snappy庫文件
    [root@hadoop101 snappy-1.1.3]# ls -lh /usr/local/lib |grep snappy
  4. 編譯安裝protobuf
    [root@hadoop101 software]# tar -zxvf protobuf-2.5.0.tar.gz -C /opt/module/
    [root@hadoop101 module]# cd protobuf-2.5.0/
    [root@hadoop101 protobuf-2.5.0]# ./configure
    [root@hadoop101 protobuf-2.5.0]# make
    [root@hadoop101 protobuf-2.5.0]# make install
  5. 查看protobuf版本以測試是否安裝成功
    [root@hadoop101 protobuf-2.5.0]# protoc --version
  6. 編譯hadoop native
    [root@hadoop101 software]# tar -zxvf hadoop-2.7.2-src.tar.gz
    [root@hadoop101 software]# cd hadoop-2.7.2-src/
    [root@hadoop101 software]# mvn clean package -DskipTests -Pdist,native -Dtar -Dsnappy.lib=/usr/local/lib -Dbundle.snappy

執行成功後,/opt/software/hadoop-2.7.2-src/hadoop-dist/target/hadoop-2.7.2.tar.gz即爲新生成的支持snappy壓縮的二進制安裝包。

壓縮配置

hadoop支持的壓縮格式
在這裏插入圖片描述
爲了支持多種壓縮/解壓縮算法,Hadoop引入了編碼/解碼器,如下表所示:
在這裏插入圖片描述
在這裏插入圖片描述
要在Hadoop中啓用壓縮,可以配置如下參數(mapred-site.xml文件中):
在這裏插入圖片描述

開啓Map輸出階段壓縮

開啓map輸出階段壓縮可以減少job中map和Reducetask間數據傳輸量。具體配置如下:
案例實操:

  1. 開啓hive中間傳輸數據壓縮功能

hive (default)>set hive.exec.compress.intermediate=true;

  1. 開啓mapreduce中map輸出壓縮功能

hive (default)>set mapreduce.map.output.compress=true;

  1. 設置mapreduce中map輸出數據的壓縮方式

hive (default)>set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;

  1. 執行查詢語句

hive (default)> select count(ename) name from emp;

開啓Reduce輸出階段壓縮

當Hive將輸出寫入到表中時,輸出內容同樣可以進行壓縮。屬性hive.exec.compress.output控制着這個功能。用戶可能需要保持默認設置文件中的默認值false,這樣默認的輸出就是非壓縮的純文本文件了。用戶可以通過在查詢語句或執行腳本中設置這個值爲true,來開啓輸出結果壓縮功能。
案例實操:

  1. 開啓hive最終輸出數據壓縮功能

hive (default)>set hive.exec.compress.output=true;

  1. 開啓mapreduce最終輸出數據壓縮

hive (default)>set mapreduce.output.fileoutputformat.compress=true;

  1. 設置mapreduce最終數據輸出壓縮方式

hive (default)> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;

  1. 設置mapreduce最終數據輸出壓縮爲塊壓縮

hive (default)> set mapreduce.output.fileoutputformat.compress.type=BLOCK;

  1. 測試一下輸出結果是否是壓縮文件

hive (default)> insert overwrite local directory
‘/opt/module/datas/distribute-result’ select * from emp distribute by deptno sort by empno desc;

文件存儲格式

Hive支持的存儲數的格式主要有:TEXTFILESEQUENCEFILEORCPARQUET
下圖左邊爲邏輯表,右邊第一個爲行式存儲,第二個爲列式存儲。
在這裏插入圖片描述
行列存儲特點:

textfilesequencefile的存儲格式都是基於存儲的;
orcparquet是基於式存儲的。

  1. 行存儲的特點

查詢滿足條件的一整行數據的時候,列存儲則需要去每個聚集的字段找到對應的每個列的值,行存儲只需要找到其中一個值,其餘的值都在相鄰地方,所以此時行存儲查詢的速度更快。

  1. 列存儲的特點

因爲每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量;每個字段的數據類型一定是相同的,列式存儲可以針對性的設計更好的設計壓縮算法。

主流文件存儲格式對比實驗

從存儲文件的壓縮比和查詢速度兩個角度對比。

  1. TextFile

create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by ‘\t’
stored as textfile ;
hive (default)> load data local inpath ‘/opt/module/datas/log.data’ into table log_text ;
hive (default)> dfs -du -h /user/hive/warehouse/log_text;
18.1 M /user/hive/warehouse/log_text/log.data

  1. ORC

create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by ‘\t’
stored asorc ;
hive (default)> insert into table log_orc select * from log_text ;
hive (default)> dfs -du -h /user/hive/warehouse/log_orc/ ;
2.8 M /user/hive/warehouse/log_orc/000000_0

  1. Parquet

create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by ‘\t’
stored as parquet ;
hive (default)> insert into table log_parquet select * from log_text ;
hive (default)> dfs -du -h /user/hive/warehouse/log_parquet/ ;
13.1 M /user/hive/warehouse/log_parquet/000000_0

存儲文件的壓縮比總結:ORC > Parquet > textFile
存儲文件的查詢速度總結:查詢速度相近。
在實際的項目開發當中,hive表的數據存儲格式一般選擇:orc或parquet。壓縮方式一般選擇snappy,lzo。

9. 調優

1. Fetch抓取

Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。例如:SELECT * FROM employees;在這種情況下,Hive可以簡單地讀取employee對應的存儲目錄下的文件,然後輸出查詢結果到控制檯。
在hive-default.xml.template文件中hive.fetch.task.conversion默認more,老版本hive默認是minimal,該屬性修改爲more以後,在全局查找字段查找limit`查找等都不走mapreduce。

  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;

  1. 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;

2. 本地模式

大多數的Hadoop Job是需要Hadoop提供的完整的可擴展性來處理大數據集的。不過,有時Hive的輸入數據量是非常小的。在這種情況下,爲查詢觸發執行任務消耗的時間可能會比實際job的執行時間要多的多。對於大多數這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務。對於小數據集,執行時間可以明顯被縮短。

用戶可以通過設置hive.exec.mode.local.auto=true,來讓Hive在適當的時候自動啓動這個優化。

set hive.exec.mode.local.auto=true;  //開啓本地mr
//設置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)

  1. 關閉本地模式,並執行查詢語句

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)

3. 表優化
小表、大表Join

將key相對分散,並且數據量小的表放在join的左邊,這樣可以有效減少內存溢出錯誤發生的機率;再進一步,可以使用map join讓小的維度表(1000條以下的記錄條數)先進內存。在map端完成reduce。
實際測試發現:新版的hive已經對小表JOIN大表和大表JOIN小表進行了優化。小表放在左邊和右邊已經沒有明顯區別。
psset hive.auto.convert.join 默認是true 打開的。

大表Join大表
  1. 空KEY過濾
    有時join超時是因爲某些key對應的數據太多,而相同key對應的數據都會發送到相同的reducer上,從而導致內存不夠。此時我們應該仔細分析這些異常的key,很多情況下,這些key對應的數據是異常數據,我們需要在SQL語句中進行過濾。例如key對應的字段爲空(開啓Hadoop 的任務歷史查看功能sbin/mr-jobhistory-daemon.sh start historyserver)

hive (default)> insert overwrite table jointable select n.* from nullidtable n left join ori o on n.id = o.id;
insert overwrite table jointable select n.* from (select * from nullidtable where id is not null) n left join ori o on n.id = o.id;

  1. 空key轉換
    有時雖然某個key爲空對應的數據很多,但是相應的數據不是異常數據,必須要包含在join的結果中,此時我們可以表a中key爲空的字段賦一個隨機的值,使得數據隨機均勻地分不到不同的reducer上。例如:

set mapreduce.job.reduces = 5;
insert overwrite table jointable select n.* from nullidtable n left join ori b on n.id = b.id; 執行後你發現5個reduce 任務耗時差別挺大。
insert overwrite table jointable select n.* from nullidtable n full join ori o on case when n.id is null then concat(‘hive’, rand()) else n.id end = o.id; 通過這個操作可以實現均衡reduce任務耗時。

MapJoin

如果不指定MapJoin或者不符合MapJoin的條件,那麼Hive解析器會將Join操作轉換成Common Join,即:在Reduce階段完成join。容易發生數據傾斜。可以用MapJoin把小表全部加載到內存在map端進行join,避免reducer處理。

  1. 設置自動選擇Mapjoin

set hive.auto.convert.join = true; 默認爲true

  1. 大表小表的閾值設置(默認25M一下認爲是小表):

set hive.mapjoin.smalltable.filesize=25000000;

在這裏插入圖片描述

Group By

默認情況下,Map階段同一Key數據分發給一個reduce,當一個key數據過大時就傾斜了。並不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進行部分聚合,最後在Reduce端得出最終結果。
開啓Map端聚合參數設置

  1. 是否在Map端進行聚合,默認爲True

hive.map.aggr = true

  1. 在Map端進行聚合操作的條目數目

hive.groupby.mapaggr.checkinterval = 100000

  1. 有數據傾斜的時候進行負載均衡(默認是false)

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中),最後完成最終的聚合操作。

Count(Distinct) 去重統計

數據量小的時候無所謂,數據量大的情況下,由於COUNT DISTINCT操作需要用一個Reduce Task來完成,這一個Reduce需要處理的數據量太大,就會導致整個Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換:

set mapreduce.job.reduces = 5;
set mapreduce.job.reduces = 5;
select count(id) from (select id from bigtable group by id) a;

笛卡爾積

儘量避免笛卡爾積,join的時候不加on條件,或者無效的on條件,Hive只能使用1個reducer來完成笛卡爾積。

行列過濾

列處理:在SELECT中,只拿需要的列,如果有,儘量使用分區過濾,少用SELECT *。
行處理:在分區剪裁中,當使用外關聯時,如果將副表的過濾條件寫在Where後面,那麼就會先全表關聯,之後再過濾,比如:

select o.id from bigtable b join ori o on o.id = b.id where o.id <= 10;
select b.id from bigtable b join (select id from ori where id <= 10 ) o on b.id = o.id;

動態分區調整

關係型數據庫中,對分區表Insert數據時候,數據庫自動會根據分區字段的值,將數據插入到相應的分區中,Hive中也提供了類似的機制,即動態分區(Dynamic Partition),只不過,使用Hive的動態分區,需要進行相應的配置。

  1. 開啓動態分區功能(默認true,開啓)

hive.exec.dynamic.partition=true

  1. 設置爲非嚴格模式(動態分區的模式,默認strict,表示必須指定至少一個分區爲靜態分區nonstrict模式表示允許所有的分區字段都可以使用動態分區。)

hive.exec.dynamic.partition.mode=nonstrict

  1. 在所有執行MR的節點上,最大一共可以創建多少個動態分區。

hive.exec.max.dynamic.partitions=1000

  1. 在每個執行MR的節點上,最大可以創建多少個動態分區。該參數需要根據實際的數據來設定。比如:源數據中包含了一年的數據,即day字段有365個值,那麼該參數就需要設置成大於365,如果使用默認值100,則會報錯。

hive.exec.max.dynamic.partitions.pernode=100

  1. 整個MR Job中,最大可以創建多少個HDFS文件。

hive.exec.max.created.files=100000

  1. 當有空分區生成時,是否拋出異常。一般不需要設置。

hive.error.on.empty.partition=false

demo

  1. 創建分區表

create table ori_partitioned(id bigint, time bigint, uid string, keyword string,url_rank int, click_num int, click_url string)
partitioned by (p_time bigint) row format delimited fields terminated by ‘\t’;

  1. 加載數據到分區表中

hive (default)> load data local inpath ‘/home/atguigu/ds1’ into table ori_partitioned partition(p_time=‘20111230000010’) ;
hive (default)> load data local inpath ‘/home/atguigu/ds2’ into table ori_partitioned partition(p_time=‘20111230000011’) ;

  1. 創建目標分區表

create table ori_partitioned_target(id bigint, time bigint, uid string,keyword string, url_rank int, click_num int, click_url string)
PARTITIONED BY (p_time STRING) row format delimited fields terminated by ‘\t’;

  1. 設置動態分區

set hive.exec.dynamic.partition = true;
set hive.exec.dynamic.partition.mode = nonstrict;
set hive.exec.max.dynamic.partitions = 1000;
set hive.exec.max.dynamic.partitions.pernode = 100;
set hive.exec.max.created.files = 100000;
set hive.error.on.empty.partition = false;
hive (default)> insert overwrite table ori_partitioned_target partition (p_time)
select id, time, uid, keyword, url_rank, click_num, click_url, p_time from ori_partitioned;

  1. 查看目標分區表的分區情況

hive (default)> show partitions ori_partitioned_target;

分桶

參考上面寫分桶即可

分區

參考上面寫分區即可

4. 數據傾斜

合理設置Map數

  1. 通常情況下,作業會通過input的目錄產生一個或者多個map任務。

主要的決定因素有:input的文件總個數,input的文件大小,集羣設置的文件塊大小。

  1. 是不是map數越多越好?

答案是否定的。如果一個任務有很多小文件( << 128M),則每個小文件也會被當做一個塊,用一個map任務來完成,而一個map任務啓動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費。而且,同時可執行的map數是受限的。

  1. 是不是保證每個map處理接近128m的文件塊,就高枕無憂了?

答案也是不一定。比如有一個127m的文件,正常會用一個map去完成,但這個文件只有一個或者兩個小字段,卻有幾千萬的記錄,如果map處理的邏輯比較複雜,用一個map任務去做,肯定也比較耗時。
針對上面的問題2和3,我們需要採取兩種方式來解決:即減少map數增加map數

小文件進行合併
在map執行前合併小文件,減少map數:CombineHiveInputFormat具有對小文件進行合併的功能(系統默認的格式)。HiveInputFormat沒有對小文件合併功能。

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

複雜文件增加Map數
當input的文件都很大,任務邏輯複雜,map執行非常慢的時候,可以考慮增加Map數,來使得每個map處理的數據量減少,從而提高任務的執行效率。
增加map的方法爲:根據computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))
blocksize=128M公式,調整maxSize最大值。讓maxSize最大值低於blocksize就可以增加map的個數。

設置最大切片值爲100個字節

hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;
hive (default)> select count(*) from emp;

合理設置Reduce數
調整reduce個數方法一

  1. 每個Reduce處理的數據量默認是256MB

hive.exec.reducers.bytes.per.reducer=256000000

  1. 每個任務最大的reduce數,默認爲1009

hive.exec.reducers.max=1009

  1. 計算reducer數的公式

N=min(參數2,總輸入數據量/參數1)

調整reduce個數方法二
在hadoop的mapred-default.xml文件中修改,設置每個job的Reduce個數

set mapreduce.job.reduces = 15;

reduce個數並不是越多越好

  1. 過多的啓動和初始化reduce也會消耗時間和資源;
  2. 另外,有多少個reduce,就會有多少個輸出文件,如果生成了很多個小文件,那麼如果這些小文件作爲下一個任務的輸入,則也會出現小文件過多的問題;
    在設置reduce個數的時候也需要考慮這兩個原則:處理大數據量利用合適的reduce數;使單個reduce任務處理數據量大小要合適;
5. 並行執行

Hive會將一個查詢轉化成一個或者多個階段。這樣的階段可以是MapReduce階段、抽樣階段、合併階段、limit階段。或者Hive執行過程中可能需要的其他階段。默認情況下,Hive一次只會執行一個階段。不過,某個特定的job可能包含衆多的階段,而這些階段可能並非完全互相依賴的,也就是說有些階段是可以並行執行的,這樣可能使得整個job的執行時間縮短。不過,如果有更多的階段可以並行執行,那麼job可能就越快完成。
通過設置參數hive.exec.parallel值爲true,就可以開啓併發執行。不過,在共享集羣中,需要注意下,如果job中並行階段增多,那麼集羣利用率就會增加。

set hive.exec.parallel=true; //打開任務並行執行
set hive.exec.parallel.thread.number=16; //同一個sql允許最大並行度,默認爲8。

當然,得是在系統資源比較空閒的時候纔有優勢,否則,沒資源,並行也起不來。

6. 嚴格模式

Hive提供了一個嚴格模式,可以防止用戶執行那些可能意想不到的不好的影響的查詢。
通過設置屬性hive.mapred.mode=nonstrict 。開啓嚴格模式需要修改hive.mapred.mode值爲strict,開啓嚴格模式可以禁止3種類型的查詢。

  1. 對於分區表,除非where語句中含有分區字段過濾條件來限制範圍,否則不允許執行。換句話說,就是用戶不允許掃描所有分區。進行這個限制的原因是,通常分區表都擁有非常大的數據集,而且數據增加迅速。沒有進行分區限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表。
  2. 對於使用了order by語句的查詢,要求必須使用limit語句。因爲order by爲了執行排序過程會將所有的結果數據分發到同一個Reducer中進行處理,強制要求用戶增加這個LIMIT語句可以防止Reducer額外執行很長一段時間。
  3. 限制笛卡爾積的查詢。對關係型數據庫非常瞭解的用戶可能期望在執行JOIN查詢的時候不使用ON語句而是使用where語句,這樣關係數據庫的執行優化器就可以高效地將WHERE語句轉化成那個ON語句。不幸的是,Hive並不會執行這種優化,因此,如果表足夠大,那麼這個查詢就會出現不可控的情況。
7. JVM重用

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都結束了纔會釋放。

8. 推測執行

在分佈式集羣環境下,因爲程序Bug(包括Hadoop本身的bug),負載不均衡或者資源分佈不均等原因,會造成同一個作業的多個任務之間運行速度不一致,有些任務的運行速度可能明顯慢於其他任務(比如一個作業的某個任務進度只有50%,而其他所有任務已經運行完畢),則這些任務會拖慢作業的整體執行進度。爲了避免這種情況發生,Hadoop採用了推測執行(Speculative Execution)機制,它根據一定的法則推測出拖後腿的任務,併爲這樣的任務啓動一個備份任務,讓該任務與原始任務同時處理同一份數據,並最終選用最先成功運行完成任務的計算結果作爲最終結果。
設置開啓推測執行參數:Hadoop的mapred-site.xml文件中進行配置

<property>
  <name>mapreduce.map.speculative</name>
  <value>true</value>
  <description>If true, then multiple instances of some map tasks 
               may be executed in parallel.</description>
</property>

<property>
  <name>mapreduce.reduce.speculative</name>
  <value>true</value>
  <description>If true, then multiple instances of some reduce tasks 
               may be executed in parallel.</description>
</property>

不過hive本身也提供了配置項來控制reduce-side的推測執行:

  <property>
    <name>hive.mapred.reduce.tasks.speculative.execution</name>
    <value>true</value>
    <description>Whether speculative execution for reducers should be turned on. </description>
  </property>

關於調優這些推測執行變量,還很難給一個具體的建議。如果用戶對於運行時的偏差非常敏感的話,那麼可以將這些功能關閉掉。如果用戶因爲輸入數據量很大而需要執行長時間的map或者Reduce task的話,那麼啓動推測執行造成的浪費是非常巨大大。

壓縮

詳細看第八章 壓縮跟存儲

10 執行計劃(Explain)
  1. 基本語法

EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query

  1. 案例實操
    查看下面這條語句的執行計劃

hive (default)> explain select * from emp;
hive (default)> explain select deptno, avg(sal) avg_sal from emp group by deptno;

查看詳細執行計劃

hive (default)> explain extended select * from emp;
hive (default)> explain extended select deptno, avg(sal) avg_sal from emp group by deptno;

10. 實戰

參考思維導圖實戰對應word即可,主要是注意編寫格式跟思路的梳理,會寫表join,炸裂函數,開窗函數。

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