Hive大總結!!!

整個hive如果要總結的非常全面的話,東西太多了,我這裏自認爲已經非常全面了。。
當然肯定會有一些瑕疵,如有不足之處,歡迎私信評論提出意見~~

覺得有幫助的,請多多支持博主,點贊關注哦~

文章目錄

Hive

一、Hive簡介及核心概念

官網:https://hive.apache.org/

1、Hive概述

Hive是構建與Hadoop之上的數據倉庫軟件,能夠有效的讀取、寫入和管理大型數據集合,並且支持通過SQL查詢分析數據。(Hive是基於Hadoop的,Hadoop數據處理任務本質上是MapReduce,所以HiveSQL執行本質上都是MapReduce任務)。

Hive:由 Facebook 開源用於解決海量結構化日誌的數據統計。
Hive 是基於 Hadoop 的一個數據倉庫工具,可以將結構化的數據文件映射爲一張表,並提供類 SQL 查詢功能。
本質是:將 HQL 轉化成 MapReduce 程序
1)Hive 處理的數據存儲在 HDFS
2)Hive 分析數據底層的實現是 MapReduce
3)執行程序運行在 Yarn 上

2、Hive特點

2.1、優點

  1. 可以通過SQL完成ETL(抽取/轉換/加載)任務、生成報表、以及數據分析。避免複雜的MapReduce的開發,能夠節省大量開發成本。
  2. Hive本質上作爲一個工具,能夠支持多種數據分析引擎。Hive可以支持Hadoop的MapReduce分析引擎,也可以支持Spark等分析引擎。
  3. Hive提供JDBC服務,可以通過JDBC連接Hive操作HDFS數據,並且可以整合多種BI可視化工具(DBeaver等)。
  4. Hive可以通過元數據直接訪問HDFS上的數據。
  5. Hive能夠支持多種數據類型和文件格式。
  6. Hive支持自定義函數,用戶可以根據需求定義自己的函數進行擴展。
  7. Hive 的執行延遲比較高,因此 Hive 常用於數據分析,對實時性要求不高的場合。
  8. Hive 優勢在於處理大數據,對於處理小數據沒有優勢,因爲 Hive 的執行延遲比較高。

2.2、缺點

  1. Hive 不支持事務操作
  2. HiveSQL本身表達能力有限,不能夠進行迭代式計算以及數據挖掘
  3. Hive操作默認基於MapReduce引擎,延遲比較高不適用於交互式查詢,並且基於SQL調優困難
  4. Hive 的效率比較低:Hive 自動生成的 MapReduce 作業,通常情況下不夠智能化;Hive 調優比較困難,粒度較粗。

2.3、Hive使用場景

  • Hive可構建基於Hadoop的數據倉庫
  • Hive適合大數據集批處理作業,比如行爲日誌分析、多維數據分析。
  • 海量結構化數據離線分析

3、Hive基本架構原理

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

從此架構圖可以看出,主要包含四個部分:

  1. Client 客戶端:Hive命令 JDBC、UI操作等,用於向系統提交查詢和其他操作。用戶接口:CLI(hive shell)、JDBC/ODBC(java 訪問 hive)、WEBUI(瀏覽器訪問 hive)。
  2. 元數據(Metastore)端:主要存儲表結構、類型、字段、數據存儲位置等信息。默認存儲在自帶的 derby 數據庫中,推薦使用 MySQL 存儲 Metastore
  3. Hadoop端:使用 HDFS 進行存儲,使用 MapReduce 進行計算。
  4. 驅動器(Driver)端:接受查詢、並且構建HiveSession回話,並且提供客戶端接口相關API。
    • 解析器(SQL Parser):將 SQL 字符串轉換成抽象語法樹 AST,這一步一般都用第三方工具庫完成,比如 antlr;對 AST 進行語法分析,比如表是否存在、字段是否存在、SQL 語義是否有誤。
    • 編譯器(Physical Plan):將 AST 編譯生成邏輯執行計劃。
    • 優化器(Query Optimizer):對邏輯執行計劃進行優化。
    • 執行器(Execution):把邏輯執行計劃轉換成可以運行的物理計劃。對於 Hive 來說,就是 MR/Spark。

4、數據處理流程

  1. 客戶端提交查詢或其他操作命令給Driver端
  2. Driver端創建Session會話,並且將查詢發送到編譯器以生成執行計劃(抽象語法樹AST)
  3. 編譯器從元存儲中獲取必要的元數據,並且對抽象語法樹AST進行類型檢查、表達式檢查、分區裁剪等
  4. 編譯器生成邏輯執行計劃,該邏輯計劃對應不同的階段Stage,每個Stage都對應一個MapReduce的Job(聚合操作)、或者是 對元數據操作(desc 操作)、或者HDFS操作(dfs)
  5. 執行器將邏輯執行計劃提交給hadoop集羣執行數據處理,並且將最終數據反饋到Driver端或者其他存儲系統。

5、Hive 和數據庫比較

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

5.1、查詢語言

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

5.2、數據存儲位置

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

5.3、數據更新

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

5.4、索引

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

5.5、執行

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

5.6、執行延遲

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

5.7、可擴展性

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

5.8、數據規模

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

二、Hive安裝及配置

1、Hive 安裝地址

  1. Hive 官網地址:http://hive.apache.org/
  2. 文檔查看地址:https://cwiki.apache.org/confluence/display/Hive/GettingStarted
  3. 下載地址:http://archive.apache.org/dist/hive/
  4. github 地址:https://github.com/apache/hive

2、Hive 安裝部署

Hive是基於Hadoop的,安裝之前的環境需要Hadoop環境,僞分佈或完全分佈或者HA都可以。

  1. 上傳壓縮包到Linux
  2. 解壓到相應目錄
  3. 修改配置文件
#修改配置文件
cp hive-env.sh.template hive-env.sh
#配置文件hive-env.sh
#配置HADOOP_HOME路徑
export HADOOP_HOME=${HADOOP_HOME}
#配置HIVE_CONF_DIR路徑
export HIVE_CONF_DIR=${HIVE_HOME}/conf
#修改日誌配置 有助於以後排查錯誤
cp hive-exec-log4j.properties.template hive-exec-log4j.properties
cp hive-log4j.properties.template hive-log4j.properties
#修改日誌文件存儲路徑
hive.log.dir=/opt/hive/log
  1. 啓動Hadoop集羣
  2. 配置環境變量
vim /etc/profile
export HIVE_HOME=/opt/hive
export PATH=$PATH:$HIVE_HOME/bin
source /etc/profile
  1. Hive基本操作
#(1)啓動 hive
[hadoop01@biubiubiu01 hive]$ hive
#(2)查看數據庫
hive>show databases;
#(3)打開默認數據庫
hive>use default;
#(4)顯示 default 數據庫中的表
hive>show tables;
#(5)創建一張表
hive> create table student(id int, name string) ;
#(6)顯示數據庫中有幾張表
hive>show tables;
#(7)查看錶的結構
hive>desc student;
#(8)向表中插入數據
hive> insert into student values(1000,"ss");
#(9)查詢表中數據
hive> select * from student;
#(10)退出 hive
hive> quit;

Hive常見的客戶端配置

#查看hive-defualt.xml 搜索/hive.cli,能夠得到客戶端的配置信息
#在hive/conf文件目錄下創建hive-site.xml,並將一下配置賦值到hive-site.xml
<configuration>
<property>
	<name>hive.cli.print.current.db</name>
	<value>true</value>
	<description>在命令行中顯示當前所使用的數據庫</description>
</property>
<property>
	<name>hive.cli.print.header</name>
	<value>true</value>
	<description>查詢數據時 顯示出列的名字</description>
</property>
</configuration>

Hive操作的數據倉庫存儲位置

<property>
	<name>hive.metastore.warehouse.dir</name>
	<value>/user/hive/warehouse</value>
	<description>默認數據倉庫存儲的位置,該位置爲HDFS上的路徑</description>
</property>
注意:需要配置用戶組和用戶執行權限
hadoop fs -chmod g+w /user/hive/warehouse

Hive日誌解析
Hive客戶端啓動時主要做了兩件事:

  1. 創建session會話,並且創建保存會話狀態的文件目錄
  2. 創建並初始化元數據存儲信息,默認創建default數據庫,默認使用DERBY嵌入式數據庫元數據

3、元數據配置

3.1、默認元數據存儲

Hive元數據默認存儲在Derby(嵌入式數據庫中)

  1. 主要應用於單元測試
  2. 一次只能連接一個用戶

3.2、Hive支持遠程關係型數據存儲

推薦使用Mysql存儲Metastore

3.3、Mysql安裝

我這裏以mysql8.0舉例,大概說明,如有安裝問題,自行百度都可以解決。

MySQL 8.0新特性:
1、默認字符集由latin1變爲utf8mb4
2、MyISAM系統表全部換成InnoDB表
3、自增主鍵AUTO_INCREMENT的值支持持久化
4、InnoDB表的DDL支持事務完整性
5、支持在線修改全局參數並持久化
6、新增降序索引
7、對於group by字段不再隱式排序
8、大幅改進了對JSON的支持
9、支持redo和undo日誌加密
10、InnoDB select for update跳過鎖等待
11、在SQL語法中增加SET_VAR語法
12、使用INVISIBLE關鍵字在創建表或進行表變更中設置索引是否可見
13、支持直方圖
14、新增innodb_dedicated_server參數
15、日誌分類更詳細
16、undo空間自動回收
17、新增資源組功能,用於調控線程優先級及綁定CPU
18、增加角色管理

1、關閉firewalld和SELinux

#關閉防火牆
[hadoop01@biubiubiu01 ~]$ sudo systemctl stop firewalld

#修改配置文件/etc/selinux/config,將其中SELINUX設置爲disabled
[hadoop01@biubiubiu01 ~]$ sudo vim /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
#SELINUX=enforcing
SELINUX=disabled
# SELINUXTYPE= can take one of three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

#查看狀態
[hadoop01@biubiubiu01 ~]$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          disabled
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      31

2、刪除CentOS 7.x自帶的MariaDB

[hadoop01@biubiubiu01 ~]$ rpm -qa | grep -i mariadb
mariadb-libs-5.5.60-1.el7_5.x86_64
[hadoop01@biubiubiu01 ~]$ sudo rpm -e --nodeps mariadb-libs-5.5.60-1.el7_5.x86_64

3、刪除原有的MySQL

1、查看mysql安裝了哪些東西
[hadoop01@biubiubiu01 ~]$ rpm -qa | grep -i mysql

2、開始卸載
[hadoop01@biubiubiu01 ~]$ sudo yum -y remove mysql57-community-release-el7-11.noarch
[hadoop01@biubiubiu01 ~]$ sudo yum -y remove mysql-community-server-5.7.29-1.el7.x86_64
[hadoop01@biubiubiu01 ~]$ sudo yum -y remove mysql-community-common-5.7.29-1.el7.x86_64
[hadoop01@biubiubiu01 ~]$ sudo yum -y remove mysql-community-client-5.7.29-1.el7.x86_64
[hadoop01@biubiubiu01 ~]$ sudo yum -y remove mysql-community-libs-5.7.29-1.el7.x86_64

3、查看是否卸載完成
[hadoop01@biubiubiu01 ~]$ rpm -qa | grep -i mysql

4、查找mysql相關目錄
[hadoop01@biubiubiu01 ~]$ sudo find / -name mysql

5、刪除相關目錄
[hadoop01@biubiubiu01 ~]$ sudo rm -rf /etc/logrotate.d/mysql /etc/selinux/targeted/active/modules/100/mysql /var/lib/mysql /var/lib/mysql/mysql /usr/bin/mysql /usr/lib64/mysql /usr/share/mysql

6、刪除/etc/my.cnf
[hadoop01@biubiubiu01 ~]$ sudo rm -rf /etc/my.cnf

7、刪除/var/log/mysqld.log(如果不刪除這個文件會導致新安裝的mysql無法存新密碼,導致無法登錄)
[hadoop01@biubiubiu01 ~]$ sudo rm -rf /var/log/mysqld.log

4、下載並安裝MySQL yum源

[hadoop01@biubiubiu01 ~]$ wget http://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
[hadoop01@biubiubiu01 ~]$ sudo rpm -ivh mysql80-community-release-el7-3.noarch.rpm

5、安裝MySQL 8.0

[hadoop01@biubiubiu01 ~]$ sudo yum -y install mysql-community-server

6、初始化MySQL 8.0

#sudo mysqld --verbose --help | less查看詳細幫助信息
[hadoop01@biubiubiu01 ~]$ sudo mysqld -I --user=mysql

7、修改/etc/my.cnf配置文件

[hadoop01@biubiubiu01 ~]$ sudo cp /etc/my.cnf /etc/my.cnf.bak
[hadoop01@biubiubiu01 ~]$ sudo vim /etc/my.cnf
#在[mysqld]配置段中新增如下代碼:
port=3306
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
skip_name_resolve=1
innodb_file_per_table=1

8、啓動MySQL 8.0

[hadoop01@biubiubiu01 ~]$ sudo systemctl start mysqld
#查看3306端口進程
[hadoop01@biubiubiu01 ~]$ sudo  netstat -anlp | grep 3306
#查看mysql服務狀態
[hadoop01@biubiubiu01 ~]$ sudo systemctl status mysqld
#設置mysql開機自啓
[hadoop01@biubiubiu01 ~]$ sudo systemctl enable mysqld

9、MySQL 8.0安全配置嚮導

[hadoop01@biubiubiu01 ~]$ sudo cat /var/log/mysqld.log | grep password
2020-02-03T08:53:17.986156Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: GkXrFH!aZ1vS
[hadoop01@biubiubiu01 ~]$ mysql_secure_installation

10、授權遠程用戶登錄

[hadoop01@biubiubiu01 ~]$ mysql -u root -p
mysql> create user 'root'@'%' identified by '123456';
#修改密碼爲永不過期
mysql> alter user 'root'@'%' identified by '123456' password expire never;
#修改密碼並指定MySQL用戶登錄密碼加密規則爲mysql_native_password
mysql> alter user 'root'@'%' identified with mysql_native_password by '123456';
mysql> grant all on *.* to 'root'@'%';
mysql> flush privileges;

11、連接客戶端測試
在這裏插入圖片描述

3.4、Hive元數據配置到Mysql

操作步驟:

  1. 將mysql的驅動程序複製到${HIVE_HOME}/lib目錄(hive2.x以上自帶)
tar -zxvf mysql-connector-java-5.1.27.tar.gz
cp mysql-connector-java-5.1.27-bin.jar ${HIVE_HOME}/lib/
  1. 創建並且配置自定義配置文件hive-site.xml
    官方配置:https://cwiki.apache.org/confluence/display/Hive/AdminManual+Metastore+Admi
    nistration
#創建配置文件
touch hive-site.xml

#配置xml文件 參考hive-defualt.xml文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
	<name>javax.jdo.option.ConnectionURL</name>
	<value>jdbc:mysql://biubiubiu01:3306/hive_metastore?createDatabaseIfNotExist=true</value>
</property>
<property>
	<name>javax.jdo.option.ConnectionDriverName</name>
	<value>com.mysql.jdbc.Driver</value>
</property>
<property>
	<name>javax.jdo.option.ConnectionUserName</name>
	<value>root</value>
</property>
<property>
	<name>javax.jdo.option.ConnectionPassword</name>
	<value>123456</value>
</property>
</configuration>
  1. 重新啓動hive客戶端
    Mysql自動創建hive_metastore數據庫
    可以開啓多個hive窗口測試
    如果出現啓動異常,檢查配置或者重新啓動虛擬機以及hadoop集羣,重點是查看Hive日誌

4、Hive配置

可以通過三種方式對 Hive 的相關屬性進行配置,分別介紹如下:

4.1 配置文件

方式一爲使用配置文件,使用配置文件指定的配置是永久有效的。Hive 有以下三個可選的配置文件:

  • hive-site.xml :Hive 的主要配置文件;

  • hivemetastore-site.xml: 關於元數據的配置;

  • hiveserver2-site.xml:關於 HiveServer2 的配置。

示例如下,在 hive-site.xml 配置 hive.exec.scratchdir

 <property>
    <name>hive.exec.scratchdir</name>
    <value>/tmp/mydir</value>
    <description>Scratch space for Hive jobs</description>
  </property>

4.2 hiveconf

方式二爲在啓動命令行 (Hive CLI / Beeline) 的時候使用 --hiveconf 指定配置,這種方式指定的配置作用於整個 Session。

hive --hiveconf hive.exec.scratchdir=/tmp/mydir

4.3 set

方式三爲在交互式環境下 (Hive CLI / Beeline),使用 set 命令指定。這種設置的作用範圍也是 Session 級別的,配置對於執行該命令後的所有命令生效。set 兼具設置參數和查看參數的功能。如下:

0: jdbc:hive2://hadoop001:10000> set hive.exec.scratchdir=/tmp/mydir;
No rows affected (0.025 seconds)
0: jdbc:hive2://hadoop001:10000> set hive.exec.scratchdir;
+----------------------------------+--+
|               set                |
+----------------------------------+--+
| hive.exec.scratchdir=/tmp/mydir  |
+----------------------------------+--+

4.4 配置優先級

配置的優先順序如下 (由低到高):
hive-site.xml - >hivemetastore-site.xml- > hiveserver2-site.xml - >-- hiveconf- > set

4.5 配置參數

Hive 可選的配置參數非常多,在用到時查閱官方文檔即可AdminManual Configuration

三、Hive運行模式

1、Hive Cli 模式

# 以命令行的形式執行 SQL
[hadoop01@biubiubiu01 ~]$ hive
hive> show databases;

# 以shell命令的形式運行
# 查看hive幫助命令
[hadoop01@biubiubiu01 ~]$ hive -help

# 執行SQL語句
[hadoop01@biubiubiu01 ~]$ hive -e 'show databases'

# 以靜默的形式執行SQL,能屏蔽掉日誌信息
[hadoop01@biubiubiu01 ~]$ hive -S -e 'show databases'

# -v 查看SQL的詳細執行情況
[hadoop01@biubiubiu01 ~]$ hive -v -e 'show databases'

# 以文件的形式執行SQL 生產環境下使用的方式
[hadoop01@biubiubiu01 ~]$ echo "show databases">1.sql
[hadoop01@biubiubiu01 ~]$ hive -f 1.sql

# 以文件的形式執行SQL 並且傳入響應的參數
[hadoop01@biubiubiu01 ~]$ vim 2.sql

輸入內容:select * from ${hivevar:tableName}
[hadoop01@biubiubiu01 ~]$ hive -f 2.sql -hivevar tableName=aa

1.1、Help

使用 hive -H 或者 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   -- 執行指定的 SQL
 -f <filename>                    SQL from files   --執行 SQL 腳本
 -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.2 交互式命令行

直接使用 Hive 命令,不加任何參數,即可進入交互式命令行。

1.3 執行SQL命令

在不進入交互式命令行的情況下,可以使用 hive -e 執行 SQL 命令。

hive -e 'select * from emp';

1.4 執行SQL腳本

用於執行的 sql 腳本可以在本地文件系統,也可以在 HDFS 上。

# 本地文件系統
hive -f /usr/file/simple.sql;

# HDFS文件系統
hive -f hdfs://hadoop001:8020/tmp/simple.sql;

其中 simple.sql 內容如下:

select * from emp;

1.5 配置Hive變量

可以使用 --hiveconf 設置 Hive 運行時的變量。

hive -e 'select * from emp' \
--hiveconf hive.exec.scratchdir=/tmp/hive_scratch  \
--hiveconf mapred.reduce.tasks=4;

hive.exec.scratchdir:指定 HDFS 上目錄位置,用於存儲不同 map/reduce 階段的執行計劃和這些階段的中間輸出結果。

1.6 配置文件啓動

使用 -i 可以在進入交互模式之前運行初始化腳本,相當於指定配置文件啓動。

hive -i /usr/file/hive-init.conf;

其中 hive-init.conf 的內容如下:

set hive.exec.mode.local.auto = true;

hive.exec.mode.local.auto 默認值爲 false,這裏設置爲 true ,代表開啓本地模式。

1.7 用戶自定義變量

--define <key=value>--hivevar <key=value> 在功能上是等價的,都是用來實現自定義變量,這裏給出一個示例:

定義變量:

hive  --define  n=ename --hiveconf  --hivevar j=job;

在查詢中引用自定義變量:

# 以下兩條語句等價
hive > select ${n} from emp;
hive >  select ${hivevar:n} from emp;

# 以下兩條語句等價
hive > select ${j} from emp;
hive >  select ${hivevar:j} from emp;

2、Hive Service2模式

#啓動Hive Service2服務
[hadoop01@biubiubiu01 ~]$ hiveserver2

#通過beeline進行連接
[hadoop01@biubiubiu01 ~]$ beeline -u jdbc:hive2://
0: jdbc:hive2://> show databases;

2.1 HiveServer2

Hive 內置了 HiveServer 和 HiveServer2 服務,兩者都允許客戶端使用多種編程語言進行連接,但是 HiveServer 不能處理多個客戶端的併發請求,所以產生了 HiveServer2。

HiveServer2(HS2)允許遠程客戶端可以使用各種編程語言向 Hive 提交請求並檢索結果,支持多客戶端併發訪問和身份驗證。HS2 是由多個服務組成的單個進程,其包括基於 Thrift 的 Hive 服務(TCP 或 HTTP)和用於 Web UI 的 Jetty Web 服務器。

HiveServer2 擁有自己的 CLI(Beeline),Beeline 是一個基於 SQLLine 的 JDBC 客戶端。由於 HiveServer2 是 Hive 開發維護的重點 (Hive0.15 後就不再支持 hiveserver),所以 Hive CLI 已經不推薦使用了,官方更加推薦使用 Beeline。

2.2 Beeline

Beeline 擁有更多可使用參數,可以使用 beeline --help 查看,完整參數如下:

Usage: java org.apache.hive.cli.beeline.BeeLine
   -u <database url>               the JDBC URL to connect to
   -r                              reconnect to last saved connect url (in conjunction with !save)
   -n <username>                   the username to connect as
   -p <password>                   the password to connect as
   -d <driver class>               the driver class to use
   -i <init file>                  script file for initialization
   -e <query>                      query that should be executed
   -f <exec file>                  script file that should be executed
   -w (or) --password-file <password file>  the password file to read password from
   --hiveconf property=value       Use value for given property
   --hivevar name=value            hive variable name and value
                                   This is Hive specific settings in which variables
                                   can be set at session level and referenced in Hive
                                   commands or queries.
   --property-file=<property-file> the file to read connection properties (url, driver, user, password) from
   --color=[true/false]            control whether color is used for display
   --showHeader=[true/false]       show column names in query results
   --headerInterval=ROWS;          the interval between which heades are displayed
   --fastConnect=[true/false]      skip building table/column list for tab-completion
   --autoCommit=[true/false]       enable/disable automatic transaction commit
   --verbose=[true/false]          show verbose error messages and debug info
   --showWarnings=[true/false]     display connection warnings
   --showNestedErrs=[true/false]   display nested errors
   --numberFormat=[pattern]        format numbers using DecimalFormat pattern
   --force=[true/false]            continue running script even after errors
   --maxWidth=MAXWIDTH             the maximum width of the terminal
   --maxColumnWidth=MAXCOLWIDTH    the maximum width to use when displaying columns
   --silent=[true/false]           be more silent
   --autosave=[true/false]         automatically save preferences
   --outputformat=[table/vertical/csv2/tsv2/dsv/csv/tsv]  format mode for result display
   --incrementalBufferRows=NUMROWS the number of rows to buffer when printing rows on stdout,
                                   defaults to 1000; only applicable if --incremental=true
                                   and --outputformat=table
   --truncateTable=[true/false]    truncate table column when it exceeds length
   --delimiterForDSV=DELIMITER     specify the delimiter for delimiter-separated values output format (default: |)
   --isolation=LEVEL               set the transaction isolation level
   --nullemptystring=[true/false]  set to true to get historic behavior of printing null as empty string
   --maxHistoryRows=MAXHISTORYROWS The maximum number of rows to store beeline history.
   --convertBinaryArrayToString=[true/false]    display binary column data as string or as byte array
   --help                          display this message

2.3 常用參數

在 Hive CLI 中支持的參數,Beeline 都支持,常用的參數如下。更多參數說明可以參見官方文檔 Beeline Command Options

參數 說明
-u <database URL> 數據庫地址
-n <username> 用戶名
-p <password> 密碼
-d <driver class> 驅動 (可選)
-e <query> 執行 SQL 命令
-f <file> 執行 SQL 腳本
-i (or)–init <file or files> 在進入交互模式之前運行初始化腳本
–property-file <file> 指定配置文件
–hiveconf property*=*value 指定配置屬性
–hivevar name*=*value 用戶自定義屬性,在會話級別有效

示例: 使用用戶名和密碼連接 Hive

$ beeline -u jdbc:hive2://localhost:10000  -n username -p password 

3、Hive直接與Hadoop交互

#通過Hive命令行與Hadoop進行交互
hive (default)> dfs -ls /

#上傳文件命令
hive (default)> dfs -put /home/hive/1.sql /

#刪除文件命令
hive (default)> dfs -rmr /1.sql

四、Hive數據類型

1、基本數據類型

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

2、集合數據類型

數據類型 描述 用法
array 存儲具有相同數據類型的一組數據
比如:[‘a’,‘b’,‘c’]
array
map 存儲一組鍵值對數據
比如:a->b c->f
map<String,Int>
struct C語言中存在一種數據結構相類似於javabean struct{name:String,age:Int}
uniontype 類似數組但是可以裝不同的數據類型 uniontype<String,int,double>

3、類型轉化

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 類型不可以轉換爲任何其它的類型。

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

五、Hive數據管理模型

元數據存儲的是Hive的數據管理模型,具體對象包括:

  • 數據庫 是表的命名空間主要負責組織管理表
  • 表信息 類似於關係型數據庫中的表,表信息包含:列、hdfs存儲位置、分區信息等
  • 分區信息 每個表可以有具有多個分區,分區個數由分區字段的數據決定
  • 分桶信息 每個分區中的數據又可以劃分爲存儲桶

注意:以上都是Hive數據的隔離機制,其中數據庫、表、分區都是以文件目錄(directory)隔離數據,分桶是以文件的形式隔離數據

1、數據庫操作

官網:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL
Hive中的每個數據庫都會映射到HDFS物理地址,其主要操作命令

  • 創建create
  • 刪除drop
  • 修改alter
  • 使用user
  • 展示show
  • 查看 desc

1.1、查看使用數據庫列表

show databases; #Hive默認會創建default庫

# 使用或者切換數據庫
語法: use 數據庫名稱
use second #切換到second數據庫

# 查看當前使用的數據庫
select current_database();

1.2、查看數據庫詳細信息

語法:desc database 名稱
#查看更新爲詳細的信息,可以展示dbproperties屬性信息
語法:desc database extended 名稱

1.3、創建數據庫

語法:
create database if not exists 名稱
COMMENT ‘數據描述信息’
LOCATION ‘指定數據庫數據存儲路徑,如果不指定則使用默認配置數據倉庫地址’
with dbproperties (key=value...) # 屬性信息
# 案例
案例1create database if not exists first_database;
#database會映射到HDFS物理地址目錄:
/user/hive/warehouse/first_database.db

案例2create database if not exists second_database comment 'test
database' location 'hdfs://biubiubiu01:9000/second' with
dbproperties('creator'='biubiubiu','createdate'='2020.01.01')

1.4、修改數據庫信息

語法:alter database database名稱 set 屬性 values
屬性:dbproperties 、location
#修改屬性
alter database second_database set dbproperties ('createtime'='2019');

#修改location屬性 版本要求:Hive 2.2.1, 2.4.0 and later
alter database second_database set location
'hdfs://biubiubiu01:9000/second2';
注意:在執行更新操作的時候,需要注意Hive的安裝版本,不同的版本可執行修改的屬性不太一樣

1.5、刪除數據庫

語法:drop database if exists 名稱 [RESTRICT|CASCADE]
RESTRICT:刪除空數據庫,默認刪除方式,不爲空時報錯
CASCADE:級聯刪除,刪除數據庫包括數據庫中的所有內容
# 案例
#數據庫爲空時
drop database if exists second_database
#數據庫不爲空時,刪除數據庫同時刪除數據庫中的內容
drop database if exists second_database CASCADE

2、數據表模型以及DDL操作

注意:以下屬性除了表名、列是必須的其他的均可以使用默認值

2.1、數據表操作

表修飾符(三種):

  1. managed管理表:hive負責管理表以及表中的數據 默認形式
  2. external外部表:Hive外部表不管理表中的數據,只管理外部表元數據,刪除外部表數據不會從文件系統中刪除,刪除表的元數據,這樣能夠有效的保護數據防止誤操作將數據刪除掉。
  3. temporary臨時表:只對當前會話有效,會話結束後會自動刪除。並且臨時表不支持分區列
2.1.1、查看錶詳細信息
語法:desc extended|formatted 表名或者表名.列名
#查看錶中列信息
desc student;

#查看錶詳細信息
desc extended student;

#查看列的詳細信息
desc extended student.name

#查看格式化詳細信息
desc formatted student

語法:查看錶創建信息
show create table 表名;
2.1.2、創建表
#創建managed表操作
create table if not exists student(name string,age int) row format delimited fields terminated by '\t'; #行中每列數據都是以 \t爲分隔符分開的

#創建外部表操作
create external table if not exists student2(name string,age int) row format delimited fields terminated by '\t';

#創建臨時表
create temporary table if not exists student2(name string,age int) row format delimited fields terminated by '\t';
2.1.3、修改表信息

根據表模型的組成,表的任何部分都可以進行修改。

#修改表名
語法:ALTER TABLE table_name RENAME TO new_table_name
案例:alter table page_view rename to new_page_view

#增加、修改和刪除表分區
語法:
增加分區:alter table 表名 add partition (key=value) location '' partiton(key=value) location '';
案例:alter table page_view add partition(dt=20200108);

交換分區: 將t2中的分區轉給T1
ALTER TABLE T1 EXCHANGE PARTITION (partition_spec) WITH TABLE T2;
案列:ALTER TABLE page_view EXCHANGE PARTITION(dt=20200104) with table page_view5;

刪除分區:
ALTER TABLE table_name DROP PARTITION(key=value)
案例: alter table page_view drop partition(dt=20200101);

#列操作:增加、更新、替換列
語法:
ALTER TABLE table_name ADD/REPLACE columns(columnName dataType,....)
案例:alter table page_view add columns(hostName string,referurl string);

replace操作很危險,將會刪除掉表中所有字段並且創建新的字段,使用前最好備份表結構
alter table page_view replace columns(hostName int);

更新刪除列:
ALTER TABLE table_name CHANGE COLUMN col_old_name col_new_name column_type
案例: alter table page_view change hostName host string;

刪除表: drop table page_view;
2.1.4、刪除表
語法:drop table 表名 [purge]
purge :意味着刪除表時直接刪除數據不會進入垃圾箱
drop table student; #同時刪除目錄以及目錄下的數據
drop table student2; #外部表只刪除元數據不刪除表目錄以及目錄下的數據,有效的保護數據
2.1.5、清空表數據
語法:truncate table 表名 #只清除數據不刪除目錄
舉例:truncate table student;
注意:該操作只能作用managed表,不能刪除外部表中數據

3、Hive分區表

hive分區表,是按照分區字段將一個表切分成不同的分區,每個分區包含表中部分數據。並且每個分區會單獨創建數據目錄。當然分區列可以有多個。

3.1、概念

Hive 中的表對應爲 HDFS 上的指定目錄,在查詢數據時候,默認會對全表進行掃描,這樣時間和性能的消耗都非常大。

分區爲 HDFS 上表目錄的子目錄,數據按照分區存儲在子目錄中。如果查詢的 where 字句的中包含分區條件,則直接從該分區去查找,而不是掃描整個表目錄,合理的分區設計可以極大提高查詢速度和性能。

這裏說明一下分區表並 Hive 獨有的概念,實際上這個概念非常常見。比如在我們常用的 Oracle 數據庫中,當表中的數據量不斷增大,查詢數據的速度就會下降,這時也可以對錶進行分區。表進行分區後,邏輯上表仍然是一張完整的表,只是將表中的數據存放到多個表空間(物理文件上),這樣查詢數據時,就不必要每次都掃描整張表,從而提升查詢性能。

3.2、使用場景

通常,在管理大規模數據集的時候都需要進行分區,比如將日誌文件按天進行分區,從而保證數據細粒度的劃分,使得查詢性能得到提升。

3.3、創建分區表

基本語法:

create table if not exists table_name(
	columeName dataTye ...
) partitioned by(columeName dataType comment '', ...)

操作案例:

create table page_view(
	userid bigint,
	page_url string,
	ip string
) partitioned by (dt string)
row format delimited fields terminated by '\t';

3.4、導入數據到分區表

基本語法:

load data local inpath ‘數據path’ into table ${tableName} partition(分區字段=);

操作案例:

導入數據:
load data local inpath ‘data_path’ into table page_view partition(dt='20200101');

查看hdfs路徑:
	在page_view路徑下會創建dt=20200101子路徑存儲數據

將數據導入到不同分區
load data local inpath ‘page_view’ into table page_view partition(dt='20200102');

3.5、查看分區表分區個數

基本語法:

show partitions ${table_name};

操作案例:

show partitions page_view;

3.6、創建二級分區表

如果一個分區列無法滿足分區需求,或者數據本身要求多列分區,則需要構建多個分區列。

#創建表 構建兩個分區字段
create table page_view2(
	userid bigint,
	page_url string,
	ip string
) partitioned by (dt string,country string)
row format delimited fields terminated by '\t';
#導入數據
load data local inpath '/home/page_view.txt' into table page_view2 partition(dt=20200101,country='china');

表現:hdfs路徑在dt路徑下創建二級目錄country路徑
page_view/dt=20200101/country='china'

3.7、動態分區

  • 官網:https://cwiki.apache.org/confluence/display/Hive/DynamicPartitions
  • 概念:
    • 靜態分區:在導入數據或者插入數據時已經明確分區字段的值
    • 動態分區:在執行過程中才能明確數據所在分區,並將數據存放在不同分區中。
  • 操作步驟:
    • 創建一張臨時表,並且將數據文件導入到臨時表中
    • 設置必要參數(hive-defualt.xml中默認值)
    • 創建分區表,並且將數據從臨時表中導入到分區表
  • 具體實現:
#創建臨時表
create external table tmp_page_view(`viewtime` bigint,`userid` bigint,`page_url` string,`ip` string,dt String) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/tzb/data/page_view2.txt' into table tmp_page_view;

#設置必要參數
set hive.exec.dynamic.partition=true
set hive.exec.dynamic.partition.mode=nostrict

#創建分區表
create external table page_view5(`viewtime` bigint,`userid` bigint,`page_url` string,`ip` string)partitioned by (dt string) row format delimited fields terminated by '\t';

#導入數據
insert into table page_view5 partition(dt) select viewtime,userid,page_url,ip, dt from tmp_page_view;

注意:
	1.動態分區列必須在select最後指定,而且列的順序需要與建表時保持一致
	2.如果分區字段數據爲空,hive會創建特殊分區dt=__HIVE_DEFAULT_PARTITION__

關於動態分區的配置參數 可以在hive-default.xml文件中查看, 搜索:dynamic.partition

3.8、清除分區數據

語法:truncate table 表名 partition(dt=value)
#清除分區數據
案例:truncate table page_view partition(dt=20200101)

4、Hive分桶表

4.1、分桶表簡介

分區提供了一個隔離數據和優化查詢的可行方案,但是並非所有的數據集都可以形成合理的分區,分區的數量也不是越多越好,過多的分區條件可能會導致很多分區上沒有數據。同時 Hive 會限制動態分區可以創建的最大分區數,用來避免過多分區文件對文件系統產生負擔。鑑於以上原因,Hive 還提供了一種更加細粒度的數據拆分方案:分桶表 (bucket Table)。

分桶表會將指定列的值進行哈希散列,並對 bucket(桶數量)取餘,然後存儲到對應的 bucket(桶)中。

4.2、分桶表理解

單從概念上理解分桶表可能會比較晦澀,其實和分區一樣,分桶這個概念同樣不是 Hive 獨有的,對於 Java 開發人員而言,這可能是一個每天都會用到的概念,因爲 Hive 中的分桶概念和 Java 數據結構中的 HashMap 的分桶概念是一致的。

當調用 HashMap 的 put() 方法存儲數據時,程序會先對 key 值調用 hashCode() 方法計算出 hashcode,然後對數組長度取模計算出 index,最後將數據存儲在數組 index 位置的鏈表上,鏈表達到一定閾值後會轉換爲紅黑樹 (JDK1.8+)。下圖爲 HashMap 的數據結構圖:
在這裏插入圖片描述

4.3、基本語法

create table 表名(
	列名 數據類型...
) partition by (列名 數據類型)
clustered by (列名) #注意這裏的列名,必須是非分區列
into 分桶個數 buckets;

4.4、操作案例

  • 案例實現步驟
    • 創建臨時表 tmp_user_info,並且導入數據
    • 創建分區分桶表user_info_bucket,分桶字段userId,數量10
    • 設置必要參數支持:set hive.enforce.bucketing = true
    • 通過insert select方式 將臨時表中數據導入到表user_info_bucket
  • 具體實現
#創建臨時表 tmp_user_info,並且導入數據
create temporary table tmp_user_info(userId bigint,firstName string,lastName string) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/biubiubiu01/data/user_info_bucket.txt' into table tmp_user_info;

#驗證導入是否成功
select * from tmp_user_info limit 10

#創建分區分桶表user_info_bucket,分桶字段userId,數量10
create table user_info_bucket(userId bigint,firstName string,lastName string) PARTITIONED BY(ds STRING) CLUSTERED BY(userId) INTO 10 BUCKETS row format delimited fields terminated by '\t';

#通過insert select方式 將臨時表中數據導入到表user_info_bucket
#設置必要參數支持 並且會開啓響應數量的reducers task數量 數量與分桶數量相同
set hive.enforce.bucketing = true

#插入數據
insert overwrite table user_info_bucket partition(ds=20200102) select userid,firstname,lastname from tmp_user_info;

#hadoop執行日誌:
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 10 (與分桶數據相同)

查看hdfs文件:
	user_info_bucket/ds=20200102/10個文件

4.5、實現原理

bucket數由表達式 hash_function(bucketing_column)/ num_buckets確定,
比如:user_info_bucket 以userId分區,實際上調用hash_bigInt(userId)/10。

問題:
分桶實際上是基於Hash算法進行實現,基於Hash算法實現就必然會遇到數據傾斜的問題。
也就意味着某個分桶文件中數據可能會很多,其他分桶文件中數據量少,可能會產生小文件!

解決思路:
比如有key:a、b、c、d、e、f 有6個key,其中a、b、c數據量相當,d、e、f數據量小,並且分桶數量4,
可以把a、b、c、分在不同桶,把d、e、f分在一個桶,這樣就能夠解決以上問題

5、傾斜表(有bug存在)

5.1、傾斜表簡介

5.2、基本語法

語法:
create table 表名(
	列名 數據類型...
) partition by (列名 數據類型)
skewed by(列名) on (傾斜的鍵...) stored as directories

5.3、操作案例

  • 操作步驟:
    • 創建臨時表 tmp_list_bucket_single,並且導入數據
    • 創建分區傾斜表 list_bucket_single,設置傾斜字段
    • 設置必要參數支持:set hive.mapred.supports.subdirectories = true;
    • 通過insert select方式 將臨時表中數據導入到表list_bucket_single
  • 具體實現:
#創建臨時表
CREATE temporary TABLE tmp_list_bucket_single (key STRING, value STRING) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/biubiubiu/data/list_bucket_single.txt' into table tmp_list_bucket_single;

#創建分區傾斜表 list_bucket_single
CREATE TABLE list_bucket_single (key STRING, value STRING) SKEWED BY (key) ON (1,5,6) stored as directories row format delimited fields terminated by '\t';

#設置參數 是否允許創建子目錄
set hive.mapred.supports.subdirectories = true;

#插入數據
insert overwrite table list_bucket_single select * from tmp_list_bucket_single;

未解決問題:無法查詢出偏斜表中的數據,該表可以管理數據,無法對數據進行讀取和分析

6、Hive行列格式

行列格式解析規則:

  • 行解析規則:row format delimited
  • 列解析規則:fields terminated by ‘\t’
  • 集合解析規則:collection items terminated by ‘,’ (默認以","號分開)
  • map解析規則: map keys terminated by ‘,’ (默認以","號分開,key與value之間以:號分開 ;)

注意:Hive讀取行數據不僅僅可以根據不同規則,也可以根據不同的序列化和返序列化器讀取行數據,其主要取決於Hive讀取數據文件的格式。

7、Hive文件存儲格式

7.1、概述

7.1.1、Hive支持的文件格式
  • TEXTFILE 格式:CSV、JSON、Txt等文件
  • SEQUENCEFILE 二進制文件
  • 列式存儲方式:ORC, PARQUET
  • 序列化文件:AVRO , AVROFILE

注意:TEXTFILE和SEQUENCEFILE的存儲格式都是基於行存儲的,
ORC和PARQUET是基於列式存儲的,但其並不是完全列式存儲,
以上文件存儲格式 在進行"行"解析的時候需要不同的序列化和反序列化器讀取。

7.1.2、序列化基本語法
create table 表名(
	列名 數據類型...
)
ROW FORMAT SERDE '序列化器' STORED AS ${文件格式}

注意:特定存儲格式的序列化器可以省略

7.1.3、列式存儲與行式存儲區別
  • 行式存儲:以行爲單位組織數據,行的數據是在相鄰位置存儲。在進行OLAP分析時,獲取數據是以行爲單位獲取數據的,會造成不必要的數據輸入以及列裁剪操作。但是在對於整行數據查詢操作時,查詢效率更高。
  • 列式存儲:以列爲單位組織數據,相同列是相鄰存儲的。在進行OLAP分析時,獲取數據是以列爲單位獲取的,獲取的僅僅是必要的列的數據,這樣能夠有效的減少數據攝入。並且每列數據具有統一的數據格式,針對不同列的不同數據格式,可以選擇不同的壓縮算法進行數據壓縮,進一步降低IO和存儲。但是對於行級別的查詢,查詢效率較低

7.2、Json格式

#json數據
{"name":"Michael"}
{"name":"Andy","age":30}
{"name":"Justin", "age":19}

#添加依賴jar包文件到hive/lib下,重新啓動hive。(hive2.x以上不用)
hive-hcatalog-core.jar

#創建表
create table jsonTable(name string,age int)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE;
注意:不添加jar文件,則會出現異常

#導入數據
load data local inpath '/home/biubiubiu/data/people.json' into table jsonTable;

#查詢數據
select name,age from jsonTable

7.3、ORC格式

1、官網https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC

2、ORC文件:Optimized Row Columnar (ORC) file,列式存儲文件。支持多種壓縮方式、並且具有很高的壓縮比,能夠支持複雜的數據類型存儲。ORC文件也是以二進制方式存儲的,所以是不可以直接讀取。

3、ORC文件結構
一個ORC文件分爲兩部分stripes(多個)和FileTail(FileFooter、PostScript)

  • stripe :ORC包含多個stripes,每個stripe大小約爲250M,相當於HDFS塊大小,其包含三部分:
    • index Data:基於RowData構建的索引信息,默認1萬行構建一個索引
    • Row Data:存的是具體的數據。Row Data分成多個RowGroup,每個RowGroup默認1萬行,RowGroup是按照列式進行數據存儲的。RowGroup中每一列都是一個stream,每個stream包含又包含了metadatastream(元數據)和DataStream(具體數據)兩類數據
    • stripe footer:包含當前stripe統計信息、Stream描述信息等
  • FileTail
    • PostScript:文件的描述信息、壓縮格式、元數據長度、版本等信息
    • Footer:文件描述信息、stripes元數據、schame元數據以及一些統計數據。

ORC文件中保存了三個層級的統計信息和索引信息

  • file level (文件級別)
  • stripe level(stripe級別)
  • row level(Row Group級別)

依據ORC文件特點:ORC文件讀取數據速度很快,能夠有效降低Hadoop數據存儲空間和加速Hive查詢速度,但是其寫入速度偏低。

4、Hive對ORC文件支持操作:

#創建臨時表並且導入game_login_data文件
create temporary table tmp_table(`loginid` string, `userid` string, `username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/biubiubiu/data/game_login_data' into table tmp_table;

#檢查數據
select * from tmp_table limit 10;

#創建基於orc存儲的表
create table orc_table(`loginid` string, `userid` string, `username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) STORED AS orc;

#導入數據
insert overwrite table orc_table select * from tmp_table;

寫文件速度orc: 26.192 s
訪問HDFS文件系統:http://biubiubiu01:50070 查看文件大小
textfile:85.3k orc:18k
統計查詢:
select loginSrc,count(distinct userId) from orc_table group by loginSrc;
textfile:24s orc:20s

7.4、Parquet格式

1、官網https://cwiki.apache.org/confluence/display/Hive/Parquet

2、parquet:是面向分析型業務的列式存儲格式,也是以二進制方式存儲數據的,能夠支持多種數據分析引擎和數據計算引擎。支持多種壓縮方式和編碼方案,通過嵌套的方式支持複雜數據類型。

3、parquet文件格式

  • 每個文件包含有一個或者多個Row Group組成,Row Group由數據集中每個列的列塊組成,每個列塊又包含一個或者多個page。
  • Row Group:行組大小一般會根據HDFS塊大小進行設計,這樣能夠保證每個mapTask處理數據的最小單位爲行組,這樣能夠有效的增大任務執行並行度。
  • Magic Code:主要用來檢查當前文件類型
  • Footer:存儲文件的描述信息、數據偏移量、行組的元數據信息和文件Schame信息。
  • Page:在parquet中有三種頁類型:數據頁、字典頁和索引頁。數據頁用於存儲當前行組中該列的值,字典頁存儲該列值的編碼字典,索引頁用來存儲當前行組下該列的索引。

4、Hive存儲Parquet數據

#創建臨時表並且導入game_login_data文件
create temporary table tmp_table(`loginid` string, `userid` string, `username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/biubiubiu/data/game_login_data' into table tmp_table;

#檢查數據
select * from tmp_table limit 10;

#創建基於parquet存儲的表
create table parquet_table(`loginid` string, `userid` string,`username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) STORED AS parquet;

#導入數據
insert overwrite table parquet_table select * from tmp_table;

寫文件速度:16.754
訪問HDFS文件系統:http://biubiubiu01:50070 查看文件大小
textfile:85.3k parquet:154.75k
統計查詢:
select loginSrc,count(distinct userId) from parquet_table group by loginSrc;
textfile:24s parquet:21.933s

5、parquet與orc對比
parquet 能夠適用於多種平臺,是與平臺無關的存儲格式,相對orc更爲通用,並且parquet格式寫效率都會略高於orc,所以如果需要在讀寫直接尋找平衡的話,parquet是不錯的選擇,並且很多數據處理框架都講parquet作爲其默認存儲格式。

8、文件壓縮方式

8.1、概述

在某些情況下,將數據壓縮在Hive表中的性能比未壓縮的存儲更好。在磁盤使用率和查詢性能方
面。

Hive依賴於Hadoop支持壓縮方式:

#查看文件的壓縮方式
hadoop checknative -a
注意:根據hadoop版本不同,其默認支持的壓縮方式也不一樣

在這裏插入圖片描述
爲了支持多種壓縮/解壓縮算法,Hadoop 引入了編碼/解碼器,如下表所示
在這裏插入圖片描述
壓縮性能的比較
在這裏插入圖片描述

Hadoop默認情況下可能不能夠全部支持以上壓縮方式,此時我們需要根據源碼進行自編譯Hadoop,並且將Hadoop/lib/native目錄下的文件拷貝到以安裝Hadoop的對應目錄下重新啓動hadoop,則可以看到更多的壓縮方式

8.2、案例:使用壓縮方式導入數據

  • 以列式存儲文件ORC和PARQUET爲例:
    • ORC:支持NONE,ZLIB, SNAPPY壓縮,默認爲ZLIB壓縮方式
    • parquet:支持LZO、SNAPPY壓縮,默認爲SNAPPY壓縮方式
  • 設置文件壓縮方式
tblproperties("文件類型.compress" ="壓縮方式")
案例:
tblproperties("org.compress" ="NONE") #設置無壓縮方式
tblproperties("org.compress" ="SNAPPY")# 設置Snappy壓縮方式

操作步驟:

  • 創建臨時表並導入響應數據
create temporary table tmp_table(`loginid` string, `userid` string,`username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) row format delimited fields terminated by'\t';

load data local inpath '/home/biubiubiu/data/game_login_data' into table tmp_table;
  • 創建以orc爲存儲格式的表(兩個:採用壓縮和不採用壓縮)
#不採用壓縮的方式
create table orc_table(`loginid` string, `userid` string, `username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) STORED AS orc tblproperties("orc.compress" ="NONE");
#採用壓縮的方式
create table orc_table_snappy(`loginid` string, `userid` string, `username` string, `rolename` string,`loginip` string,`loginsrc` string,`logintime` string) STORED AS orc tblproperties("orc.compress" ="SNAPPY");
  • 導入數據到ORC表中
insert overwrite table orc_table select * from tmp_table;
insert overwrite table orc_table_snappy select * from tmp_table;
  • 查看HDFS Web界面 兩個文件目錄數據大小的對比情況

依據以上步驟 可以測試其他壓縮方式 比如ZLIB
開發過程中一般使用orc,Parquet存儲和snappy壓縮

9、視圖

Hive支持兩種類型視圖

  • 普通視圖:是一個虛擬表,其本身不存儲數據,數據是由查詢語句定義的。簡單來說視圖只是的定義了 數據結構的元數據。
  • 物化視圖:是一個特殊物理表,視圖本身保存數據,其數據來源是根據原始表或者是遠程表查詢而來,並且會定時更新數據。Hive目前僅3.0及以上版本支持。

9.1、簡介

Hive 中的視圖和 RDBMS 中視圖的概念一致,都是一組數據的邏輯表示,本質上就是一條 SELECT 語句的結果集。視圖是純粹的邏輯對象,沒有關聯的存儲 (Hive 3.0.0 引入的物化視圖除外),當查詢引用視圖時,Hive 可以將視圖的定義與查詢結合起來,例如將查詢中的過濾器推送到視圖中。

9.2、創建視圖

CREATE VIEW [IF NOT EXISTS] [db_name.]view_name   -- 視圖名稱
  [(column_name [COMMENT column_comment], ...) ]    --列名
  [COMMENT view_comment]  --視圖註釋
  [TBLPROPERTIES (property_name = property_value, ...)]  --額外信息
  AS SELECT ...;

在 Hive 中可以使用 CREATE VIEW 創建視圖,如果已存在具有相同名稱的表或視圖,則會拋出異常,建議使用 IF NOT EXISTS 預做判斷。在使用視圖時候需要注意以下事項:

  • 視圖是隻讀的,不能用作 LOAD / INSERT / ALTER 的目標;

  • 在創建視圖時候視圖就已經固定,對基表的後續更改(如添加列)將不會反映在視圖;

  • 刪除基表並不會刪除視圖,需要手動刪除視圖;

  • 視圖可能包含 ORDER BY 和 LIMIT 子句。如果引用視圖的查詢語句也包含這類子句,其執行優先級低於視圖對應字句。例如,視圖 custom_view 指定 LIMIT 5,查詢語句爲 select * from custom_view LIMIT 10,此時結果最多返回 5 行。

  • 創建視圖時,如果未提供列名,則將從 SELECT 語句中自動派生列名;

  • 創建視圖時,如果 SELECT 語句中包含其他表達式,例如 x + y,則列名稱將以_C0,_C1 等形式生成;

CREATE VIEW  IF NOT EXISTS custom_view AS SELECT empno, empno+deptno , 1+2 FROM emp;

9.3、查看視圖

-- 查看所有視圖: 沒有單獨查看視圖列表的語句,只能使用 show tables
show tables;
-- 查看某個視圖
desc view_name;
-- 查看某個視圖詳細信息
desc formatted view_name;

9.4、修改視圖

ALTER VIEW [db_name.]view_name AS select_statement;

被更改的視圖必須存在,且視圖不能具有分區,如果視圖具有分區,則修改失敗。

9.5、修改視圖屬性

語法:

ALTER VIEW [db_name.]view_name SET TBLPROPERTIES table_properties;
 
table_properties:
  : (property_name = property_value, property_name = property_value, ...)

示例:

ALTER VIEW custom_view SET TBLPROPERTIES ('create'='biubiubiu','date'='2019-05-05');

9.6、刪除視圖

DROP VIEW [IF EXISTS] [db_name.]view_name;

刪除視圖時,如果被刪除的視圖被其他視圖所引用,這時候程序不會發出警告,但是引用該視圖其他視圖已經失效,需要進行重建或者刪除。

10、索引

10.1、簡介

Hive 在 0.7.0 引入了索引的功能,索引的設計目標是提高表某些列的查詢速度。如果沒有索引,帶有謂詞的查詢(如’WHERE table1.column = 10’)會加載整個表或分區並處理所有行。但是如果 column 存在索引,則只需要加載和處理文件的一部分。

10.2、索引原理

在指定列上建立索引,會產生一張索引表(表結構如下),裏面的字段包括:索引列的值、該值對應的 HDFS 文件路徑、該值在文件中的偏移量。在查詢涉及到索引字段時,首先到索引表查找索引列值對應的 HDFS 文件路徑及偏移量,這樣就避免了全表掃描。

+--------------+----------------+----------+--+
|   col_name   |   data_type    | comment     |
+--------------+----------------+----------+--+
| empno        | int            |  建立索引的列  |   
| _bucketname  | string         |  HDFS 文件路徑  |
| _offsets     | array<bigint>  |  偏移量       |
+--------------+----------------+----------+--+

10.3、創建索引

CREATE INDEX index_name     --索引名稱
  ON TABLE base_table_name (col_name, ...)  --建立索引的列
  AS index_type    --索引類型
  [WITH DEFERRED REBUILD]    --重建索引
  [IDXPROPERTIES (property_name=property_value, ...)]  --索引額外屬性
  [IN TABLE index_table_name]    --索引表的名字
  [
     [ ROW FORMAT ...] STORED AS ...  
     | STORED BY ...
  ]   --索引錶行分隔符 、 存儲格式
  [LOCATION hdfs_path]  --索引表存儲位置
  [TBLPROPERTIES (...)]   --索引表表屬性
  [COMMENT "index comment"];  --索引註釋

10.4、查看索引

--顯示錶上所有列的索引
SHOW FORMATTED INDEX ON table_name;

10.5、重建索引

ALTER INDEX index_name ON table_name [PARTITION partition_spec] REBUILD;

重建索引。如果指定了 PARTITION,則僅重建該分區的索引。

10.6、刪除索引

刪除索引會刪除對應的索引表。

DROP INDEX [IF EXISTS] index_name ON table_name;

如果存在索引的表被刪除了,其對應的索引和索引表都會被刪除。如果被索引表的某個分區被刪除了,那麼分區對應的分區索引也會被刪除。

10.7、自動使用索引

默認情況下,雖然建立了索引,但是 Hive 在查詢時候是不會自動去使用索引的,需要開啓相關配置。開啓配置後,涉及到索引列的查詢就會使用索引功能去優化查詢。

SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;
SET hive.optimize.index.filter=true;
SET hive.optimize.index.filter.compact.minsize=0;

10.8、查看索引

SHOW INDEX ON emp;

在這裏插入圖片描述

10.9、索引的缺陷

索引表最主要的一個缺陷在於:索引表無法自動 rebuild,這也就意味着如果表中有數據新增或刪除,則必須手動 rebuild,重新執行 MapReduce 作業,生成索引表數據。

同時按照官方文檔 的說明,Hive 會從 3.0 開始移除索引功能,主要基於以下兩個原因:

  • 具有自動重寫的物化視圖 (Materialized View) 可以產生與索引相似的效果(Hive 2.3.0 增加了對物化視圖的支持,在 3.0 之後正式引入)。
  • 使用列式存儲文件格式(Parquet,ORC)進行存儲時,這些格式支持選擇性掃描,可以跳過不需要的文件或塊。

六、DML 數據操作

1、數據導入

1.1、向表中裝載數據(Load)

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

1.2、通過插入的方式將數據導入到表中

  • INSERT SELECT方式導入數據
語法:INSERT [OVERWRITE][INTO] 表名 SELECT COLUMNS FROM 表名
  • INSERT LOCAL SELECT方式插入數據
語法:INSERT [LOCAL][DIRECTORY] 'filePath' SELECT COLUMNS FROM 表名
  • INSERT VALUES方式插入數據
語法:INSERT INTO TABLE 表名 PARTITION(key=value) VALUES(values_row)
  • 創建表指定已經存儲數據的路徑
語法:create table 表名(columns dataType...) row format row_formate location 'hdfs路徑';

1.3、Import 數據到指定 Hive 表中

語法: import table 表名 partition(key=value) from 'souce_path'
[location 'souce_path']
注意:需要結合這export使用
export table 表名 to 'hdfs_path'

1.4、操作案例

#創建臨時表
create temporary table people(name string,age int,salary bigint) row format delimited fields terminated by ',';
#導入數據 第一種方式
load data local inpath '/home/biubiubiu/data/people.txt' into table people;
#導入數據 第二種方式
hdfs dfs -put /home/tzb/data/people.txt /hive/people.txt
load data inpath '/hive/people.txt' into table people;
#將people表導入到新表中
#創建表
create table people2 like people;
#導入數據
insert into table people2 partition by (day=20200104) select * from
people;
#多次插入
insert overwrite table people2 partition by (day=20200104) select name,age,salary where name='Michael'
insert overwrite table people2 partition by (day=20200105) select name,age,salary where name='Andy'
insert overwrite table people2 partition by (day=20200106) select name,age,salary where name='Justin'
#創建表
create table people3 like people;
#導入數據
insert overwrite directory 'hdfs://biubiubiu01:9000/user/hive/warehouse/hivedb1.db/people3' row format delimited fields terminated by ',' select * from people;
注意:列分隔符一定要與創建表時候的分割符號一致
#創建表
create table people4 like people;
#導入數據
insert into table people4 values('Michael',29,1000),('Michael',19,2000);
注意:
1.插入必須爲表中的每一列提供值
2.不支持複雜類型(數組,映射,結構,聯合)
#創建表
hadoop fs -put /home/biubiubiu/data/people.txt /test/people.txt
#創建表 通過location指定路徑
create table people5(name string,age int,salary bigint) row format delimited fields terminated by ',' location '/test/';
#通過import導入數據
#導出
export table people4 to '/export/';
import table people6 from '/export';

2、數據導出

2.1、Insert 導出

  • 將查詢的結果導出到本地
hive (default)> insert overwrite local directory '/opt/module/datas/export/student' select * from student;
  • 將查詢的結果格式化導出到本地
hive (default)> insert overwrite local directory '/opt/module/datas/export/student1' 
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
  • 將查詢的結果導出到 HDFS 上(沒有 local)
hive (default)> insert overwrite directory '/user/atguigu/student2'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
select * from student;

2.2、Hadoop 命令導出到本地

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

2.3、Hive Shell 命令導出

[hadoop01@biubiubiu01 hive]$ bin/hive -e 'select * from default.student;' > /opt/module/datas/export/student4.txt;

2.4、Export 導出到 HDFS 上

hive (default)> export table default.student to '/user/hive/warehouse/export/student';

2.5、第三方組件sqoop或者datax等將數據導出

後邊再說。

2.6、案例

#將數據導入到另一個目錄
insert overwrite directory 'hdfs://biubiubiu01:9000/user/hive/warehouse/hivedb1.db/people3' row format delimited fields terminated by ',' select * from people;
#將數據導出
hdfs dfs -get '表文件路徑' '本地路徑'
#通過export 導出數據
export table people4 to '/export/';

七、查詢操作

官網:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select

1、查詢語句及數據準備

1.1、基本語法規則

[WITH CommonTableExpression (, CommonTableExpression)*] 定義子查詢表
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] #limit 返回條數 可以接受1或者2個參數(2.0後可以接受
兩個參數)

HiveSQL寫法規範

  1. SQL大小不敏感
  2. SQL支持子查詢
  3. 字段支持運算符以及函數操作
  4. 字段、表等可以具有別名

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

1.2、數據準備

準備工作

  1. 創建模擬數據 登錄數據和充值數據,並將數據上傳到虛擬機
  2. Hive中創建表兩張臨時表以及兩張分區表
  3. 將臨時表中數據通過動態分區的方式加載到分區表中

準備工作操作

#創建用戶登錄表信息
create temporary table tmp_game_login_data(loginId String,userId String,userName String,roleName String,loginIp String,loginSrc string,loginTime string) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/biubiubiu/data/game_login_data' into table tmp_game_login_data;

#創建用戶充值表
create temporary table tmp_game_charge_data(orderId string,userId string,userName string,roleName string,chargeMoney string,chargeSrc string,chargeTime string) row format delimited fields terminated by '\t';

#導入數據
load data local inpath '/home/biubiubiu/data/game_charge_data' into table tmp_game_charge_data;

#創建分區表
create table game_login_data(loginId String,userId String,userName String,roleName String,loginIp String,loginSrc string,loginTime string) partitioned by (dt string) row format delimited fields terminated by '\t';

create table game_charge_data(orderId string,userId string,userName string,roleName string,chargeMoney int,chargeSrc string,chargeTime string) partitioned by (dt string) row format delimited fields terminated by '\t';

#將數據導入到分區表
set hive.exec.dynamic.partition=true
set hive.exec.dynamic.partition.mode=nostrict

#導入動態分區表
insert overwrite table game_login_data partition(dt) select loginId,userId,userName,roleName,loginIp,loginSrc,loginTime,date_format (loginTime,'yyyyMMdd') dt from tmp_game_login_data; insert overwrite table game_charge_data partition(dt) select orderId,userId,userName,roleName,chargeMoney,chargeSrc,chargeTime,date_format(chargeTime,'yyyyMMdd') dt from tmp_game_charge_data;

2、基本查詢

2.1、全表和特定列查詢

1)全表查詢

hive (default)> select * from emp;

2)選擇特定列查詢

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

2.2、列別名

  • 重命名一個列。
  • 便於計算。
  • 緊跟列名,也可以在列名和別名之間加入關鍵字‘AS’
  • 案例實操
# 查詢名稱和部門
hive (default)> select ename AS name, deptno dn from emp;

2.3、算術運算符

在這裏插入圖片描述

2.4、常用函數

1)求總行數(count)
hive (default)> select count(*) cnt from emp;

2)求工資的最大值(max)
hive (default)> select max(sal) max_sal from emp;

3)求工資的最小值(min)
hive (default)> select min(sal) min_sal from emp;

4)求工資的總和(sum)
hive (default)> select sum(sal) sum_sal from emp;

5)求工資的平均值(avg)
hive (default)> select avg(sal) avg_sal from emp;

2.5、Limit語句

# 查詢返回10行數據,限制返回條數
select * from game_login_data limit 10;
select * from game_charge_data limit 10;
# hive 2.0版本以後可以跟兩個參數
# 第五行到第十行
select * from game_charge_data limit 5,10;

3、Where 語句

  • where條件是一個布爾表達式,表達式支持各種比較運算符、邏輯運算符和子查詢
  • 比較運算符
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 特殊比較運算符:
    • like:模糊查詢 %:代表0個和多個字符,_:代表一個字符
    • rlike :在like基礎之上支持正則表達式
#loginId以2結尾的數據
select * from game_login_data where loginId like '%2';
#loingId第二位是2的數據
select * from game_login_data where loginId like '_2%';

#模糊查詢
select * from game_login_data where loginId rlike '[2]';
  • 邏輯運算符
    • and、or、not、in、not in、exists操作
      在這裏插入圖片描述

4、分區列裁剪

對於分區表來說,select時候通過分區字段指定查詢分區,此時查詢操作僅僅掃描指定分區數據。

5、分組聚合操作

5.1、Group by操作

分組操作 通常會和聚合函數(UDAF)一起使用,主要用來做統計彙總數據,並且可以根據多個列進
行分組

案例實操:
#需求:統計每天的登陸次數以及登陸人數
select dt, count(1) times,count(distinct userId) users from game_login_data group by dt;
#需求:統計每天充值次數、充值人數、充值金額、平均充值金額
select dt,count(1) chargeTimes,count(distinct userId) chargeUsers,sum(chargeMoney) chargeMoney,avg(chargeMoney) avgChargeMoney
from game_charge_data group by dt;

5.2、Having操作

#需求:統計每人充值次數充值金額並且充值金額大於1000的人
select userId,userName,count(1) chargeTimes,sum(chargeMoney) chargeMones
from game_charge_data group by userId,userName having chargeMones>1000;

注意:
1.having針對分組查詢結果進行篩選
2.having 後可以使用聚合函數或者聚合函數別名
3.having只能用於group by 分組統計語句

5.3、with rollup操作

#需求:統計每天每個充值渠道的充值金額,並且按照充值渠道進行彙總統計
比如:
null,null,200
null, 微信支付,200
20200102,微信支付,100
20200103,微信支付,100
select dt,chargeSrc,sum(chargeMoney) from game_charge_data group by chargeSrc,dt with rollup;

rollup:彙總操作,具有層級的彙總操作,層級彙總順序與group by後分組順序有關

以上需求 通過union all的方式就等同於
select dt,chargeSrc,sum(chargeMoney) from game_charge_data group by
chargeSrc,dt
union all
select null,chargeSrc,sum(chargeMoney) from game_charge_data group by
chargeSrc
union all
select null,null,sum(chargeMoney) from game_charge_data;
以上操作就是就涉及到多維查詢。

兩個重要概念:
	維度:觀察數據的角度,dt,chargeSrc
	度量:通過維度計算得到的數據 sum(chargeMoney)
	
多維查詢:通過0個或多個緯度進行統計分析數據操作

需求:通過dt、chargeSrc、roleName,三個維度,任意組合查詢充值數據。
1.union all的方式能寫出幾條數據?
	2^3次方條語句
dt,chargeSrc,roleName,(dt,chargeSrc),(dt,roleName),(chargeSrc,roleName),
(dt,chargeSrc,roleName) ()

5.4、with cube 多維分析操作

需求:通過dt、chargeSrc、roleName,三個維度,任意組合查詢充值數據
select dt,chargeSrc,roleName,sum(chargeMoney) from game_charge_data group by
chargeSrc,dt,roleName with cube;

cube:數據立方體,通過多維分析構建的抽象概念,類似於多維座標系概念

5.5、grouping sets 自動多維查詢

  • 基於cube操作請求,自定義緯度組合,減少數據構建次數
通過dt、chargeSrc、roleName,三個維度,只需要:(dt,chargeSrc),(dt,roleName),(dt、
chargeSrc、roleName) 維度組合統計數據
select dt,chargeSrc,roleName,sum(chargeMoney) 
from game_charge_data 
group by chargeSrc,dt,roleName 
grouping sets((dt,chargeSrc),(dt,roleName),(dt、chargeSrc、roleName));

很多情況下,多維分析需要兩個表進行關聯操作,也就是事實表和維表進行關聯,join操作語法。

6、join語句

官網:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Joins

6.1、基本語法

join_table:
table_reference [INNER] JOIN table_factor on 條件語句
| table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference 條件
| table_reference LEFT SEMI JOIN table_reference 條件
| table_reference CROSS JOIN table_reference on 條件

Join支持內連接、左鏈接、左半鏈接、右鏈接、全連接、交叉鏈接

on:關聯條件(注:hive2.2.0版本之前,不支持非等值連接,之後的版本可以支持複雜的鏈接)

6.2、內連接(inner join)

  • 內連接: 根據關聯條件取兩個表交集,即在表1中存在也在表2中存在數據
  • 案例:
#需求:查詢出在20200106登錄並且充值的人員名單
WITH t_login AS (
		SELECT DISTINCT userId, userName
		FROM game_charge_data
		WHERE dt = 20200106
	),
	t_charge AS (
		SELECT DISTINCT userId, userName
		FROM game_login_data
		WHERE dt = 20200106
)
SELECT l.userId, l.userName
FROM t_login l
	JOIN t_charge c
	ON l.userId = c.userId AND l.userName = c.userName;

6.3、左外鏈接(left join)

  • 左外鏈接:返回左表全部行和右表滿足關聯條件的行,如果左表在右表中沒有匹配,則返回NULL代替
  • left join 與left outer join是等價的,left join是簡寫方式
  • 案例:
需求:查詢20200106每個活躍用戶的用戶信息和充值金額
WITH t_login AS (
SELECT DISTINCT userId, userName
FROM game_login_data
WHERE dt = 20200106
),
t_charge AS (
SELECT userId, userName, SUM(chargeMoney) AS userCharge
FROM game_charge_data
WHERE dt = 20200106
GROUP BY userId, userName
)
SELECT l.userId, l.userName, c.userCharge
FROM t_login l
LEFT JOIN t_charge c
ON l.userId = c.userId
AND l.userName = c.userName

6.4、右外連接(right join)

  • 右外連接:返回右表的全部行和左表滿足ON條件的行,如果右表的行在左表中沒有匹配,那麼這一行左表中對應數據用NULL代替
  • 案例:
需求:查詢20200106有充值記錄但是沒有登錄的人的信息
WITH t_login AS (
SELECT DISTINCT userId, userName
FROM game_login_data
WHERE dt = 20200106
),
t_charge AS (
SELECT userId, userName, SUM(chargeMoney) AS userCharge
FROM game_charge_data
WHERE dt = 20200106
GROUP BY userId, userName
)
SELECT l.userId, l.userName, c.userId, c.userName, c.userCharge
FROM t_login l
RIGHT JOIN t_charge c
ON l.userId = c.userId
AND l.userName = c.userName;

6.5、全鏈接(fulljoin)

  • 全連接:返回左表和右表全部行,實際上就是左表和右表的並集,對於沒有匹配的記錄,以null做爲值。
  • 案例:
WITH t_login AS (
SELECT DISTINCT userId, userName
FROM game_login_data
WHERE dt = 20200106
),
t_charge AS (
SELECT userId, userName, SUM(chargeMoney) AS userCharge
FROM game_charge_data
WHERE dt = 20200106
GROUP BY userId, userName
)
SELECT l.userId, l.userName, c.userId, c.userName, c.userCharge
FROM t_login l
FULL JOIN t_charge c
ON l.userId = c.userId
AND l.userName = c.userName;

6.6、交叉鏈接(cross join)

  • 交叉鏈接:實際上就是笛卡爾乘積,左表所有行X右表所有行,如果有on條件則會進行過濾,在這裏等同於inner join操作
  • 笛卡爾集會在下面條件下產生:
    (1)省略連接條件
    (2)連接條件無效
    (3)所有表中的所有行互相連接
  • 案例:
WITH t_login AS (
SELECT DISTINCT userId, userName
FROM game_login_data
WHERE dt = 20200106
),
t_charge AS (
SELECT userId, userName, SUM(chargeMoney) AS userCharge
FROM game_charge_data
WHERE dt = 20200106
GROUP BY userId, userName
)
SELECT l.userId, l.userName, c.userId, c.userName, c.userCharge
FROM t_login l
CROSS JOIN t_charge c
ON l.userId = c.userId
AND l.userName = c.userName;

6.7、左半鏈接(left semi join)

  • 左半鏈接left semi join:用來高效的代替in /exists 語義的
  • 案例:
#登錄並且充值的用戶所有登錄記錄
select a.* from game_login_data a left semi join game_charge_data b on
(a.userId=b.userId and a.dt=20200106 and b.dt=20200106);
相當於:
with b as (select userId from game_charge_data where dt=20200106)
select a.* from game_login_data a where a.userId in (select * from b) and
a.dt=20200106

7、排序

7.1、全局排序(Order By)

Order By:全局排序,一個 MapReduce

  • 使用 ORDER BY 子句排序

    • ASC(ascend): 升序(默認)
    • DESC(descend): 降序
  • ORDER BY 子句在 SELECT 語句的結尾。

7.2、每個MapReduce內部排序(Sort By)

sort by:在多個MapReduce情況下,僅保證每個MapReduce輸出數據有序,不保證全局有序

7.3、分區排序(Distribute By)

  • Distribute By:類似 MR 中 partition,進行分區,結合 sort by 使用。

  • 注意,Hive 要求 DISTRIBUTE BY 語句要寫在 SORT BY 語句之前。

  • 對於 distribute by 進行測試,一定要分配多 reduce 進行處理,否則無法看到 distribute by的效果。

7.4、Cluster By

當 distribute by 和 sorts by 字段相同時,可以使用 cluster by 方式。
cluster by = distribute by + sorts by

cluster by 除了具有 distribute by 的功能外還兼具 sort by 的功能。但是排序只能是倒序排序,不能指定排序規則爲 ASC 或者 DESC。
1)以下兩種寫法等價

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

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

7.5、案例

#查詢20200106每人總充值,並且按照總充值排序 order by
insert overwrite local directory '/home/orderby_result' row format
delimited fields terminated by '\t'
select userId,sum(chargeMoney) userCharge from game_charge_data where
dt=20200106 group by userId order by userCharge desc;

#基於分區排序
set mapreduce.job.reduces=3 #設置reduce個數

insert overwrite local directory '/home/sortby_result' row format
delimited fields terminated by '\t'
select userId,sum(chargeMoney) userCharge from game_charge_data where
dt=20200106 group by userId sort by userCharge desc;

注意:
1.僅一個reduces的時候,order by 與sort by的執行結果一致。
2.sort by 能夠並行執行排序,可以構建中間臨時表完成order by的查詢結果

#按照userId進行分區,並且按照userCharge進行分區排序
set mapreduce.job.reduces=3 #設置reduce個數

insert overwrite local directory '/home/distributeby_result' row format
delimited fields terminated by '\t'
select userId,sum(chargeMoney) userCharge from game_charge_data where
dt=20200106 group by userId distribute by userId sort by userCharge;

#按照userCharge進行分區並且排序
set mapreduce.job.reduces=3 #設置reduce個數

insert overwrite local directory '/home/clusterby_result' row format
delimited fields terminated by '\t'
select userId,sum(chargeMoney) userCharge from game_charge_data where
dt=20200106 group by userId cluster by userCharge;

8、數據採樣

  • 採樣:對大數據集合進行數據樣品的採集,也就是隨機的獲取大數據集合的子集。通過樣品數據獲取一些代表性的數值。
  • 採樣方法:hive支持兩種採樣方法 :分桶採樣方法 塊採樣
  • 採樣關鍵詞:tablesample

8.1、分桶採樣方法

  • 分區針對的是數據的存儲路徑;分桶針對的是數據文件。
  • 分區提供一個隔離數據和優化查詢的便利方式。不過,並非所有的數據集都可形成合理的分區,特別是之前所提到過的要確定合適的劃分大小這個疑慮。
  • 分桶是將數據集分解成更容易管理的若干部分的另一個技術。
  • 基本語法:
select 字段名.. from 表 tablesmaple (bucket x out of y on 字段名colName)
colName:爲分區列,當然可以爲多個列,以“,”分開。還可以是rand()函數,隨機採樣
y: 意味着將整個表按照colName分成y個桶,編號從1到y
x: 從y個桶中取第x個桶的數據
注意: x 必須小於 y的值
此時:TABLESAMPLE將掃描整個表並獲取樣本,如果表很大可能會取樣效率會很低

第二種方式:可以將數據導入分桶表中,然後在每個分桶上進行取樣。如果clustered by 字段
名 與取樣字段名一樣,則僅僅只掃描匹配的分桶
注意:y必須是table總bucket數的倍數或者因子
比如表以id 分桶個數據爲 32,
tablesmaple (bucket 3 out of 32 on id) ,此時會直接獲取第三個分區。
tablesmaple (bucket 3 out of 16 on id) 此時取樣 10/5=2,此時會將32個桶分爲2
個數據區域,每個區域16個桶,則會分別取第三桶和第19個桶
tablesmaple (bucket 3 out of 64 on id) 此時將會掃描第三個桶的一半的數據
  • 操作案例:
一:針對非分桶表進行採樣
select * from game_login_data tablesample(bucket 1 out of 3 on userId);
驗證:
select count(1) from game_login_data tablesample(bucket 1 out of 3 on userId)
union all
select count(1) from game_login_data tablesample(bucket 2 out of 3 on userId)
union all
select count(1) from game_login_data tablesample(bucket 3 out of 3 on userId);
將以上三個分桶採樣數據累加 可以得到該表的數據量總和

二:對分通表進行採樣
#設置系統 支持分桶操作
set hive.enforce.bucketing = true;

#創建分桶表
create table bucket_game_login_data(`loginid` string,`userid`
string,`username` string,`rolename` string, `loginip` string,`loginsrc`
string,`logintime` string) clustered by(userId) into 10 buckets row
format delimited fields terminated by '\t';

#向表中插入數據
insert overwrite table bucket_game_login_data row format delimited fields terminated by '\t' 
select loginid,userid,username,rolename,loginip,loginsrc,logintime 
from game_login_data;

#採樣數據
select count(*) from bucket_game_login_data tablesample (bucket 3 out of 5 on userId);

8.2、塊採樣

  • 基於HDFS塊級別執行數據採樣,採樣粒度爲塊大小。如果採樣數據不夠成完整的塊,則依然會按照塊大小獲取數據。
  • 基本語法:
select 列名 from 表名 tablesample (n [percent,bit,rows])
percent:按照百分比取樣,至少獲取百分之n%數據,如果n%數據不構成完整的數據塊,則依然會
按照塊大小獲取數據
bit:按照數據容量取樣 n =100M 100G [B|K|M|G]percent
rows:獲取每個分區的行數 n=10 獲取每個分區的前10行。
  • 操作案例:
#採樣10%數據,實際輸入的數據大於或者等於10%
select count(1) from game_login_data tablesample(0.1 percent);
#採樣10M數據,實際輸出的數據大於或者等於10M
select count(1) from game_login_data tablesample(10m);
#獲取每個分區的前100行數據
select count(1) from game_login_data tablesample(100 rows);

9、常用函數操作

show functions; 查詢出所有函數
#查看函數用法
desc function 函數名稱;

具體操作:
desc function nvl;
返回結果:
nvl(value,default_value) - Returns default value if value is null else returns value

9.1、空字段賦值

  • 函數及用法:
nvl(value,default_value) 如果value爲空,則賦予默認值
  • 案例
#創建臨時表
create temporary table nvltest(id string);
#插入數據
insert into table nvltest values('aa'),(NULL);
#查詢數據
select nvl(id,'biubiubiu') from nvltest;

9.2、case when

  • 函數及用法:
desc function case;
CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END - When a = b,returns c; when a = d, return e; else return f
  • 案例
需求:將game_charge_data 表中chargeMoney字段 轉換成對應的金幣
比如
59 1999
99 2999
其餘轉換成 6999
select userId,chargeMoney,case chargeMoney when 59 then 1999 when 99
then 2999 when 129 then 3999 else 6999 end from game_charge_data 
where dt=20200106

9.3、行轉列

  • 函數及用法:
collect_list(列名)
該函數返回一個列表 數據格式爲array
collect_set(列名)
該函數返回一個列表 數據格式爲array,列表中不包含重複元素
  • 案例
需求:獲取game_login_data 表中每個人的行爲軌跡
select userId,collect_list(loginIp) from game_login_data where
dt=20200106 group by userId;
#獲取去重後的行爲軌跡
select userId,collect_set(loginIp) from game_login_data where
dt=20200106 group by userId;
爲了讓數據展示的友好,可以採用拼接字符串函數

9.4、字符串拼接

  • 函數及用法:
concat(str1,str2...) 將多個列按照‘,’進行拼接
concat_ws(seq,str1,str2...) 將多個列按照 seq 進行拼接,並且該函數支持array 數組拼接
  • 案例
select userId,concat_ws('|',collect_set(loginIp)) from game_login_data
where dt=20200106 group by userId;

10、窗囗函數

窗口函數:基於查詢結果的行數據進行計算。窗口函數運行在 HAVING 子句之後,在 ORDER BY子句之前。在SQL處理中,窗口函數都是最後一步執行,僅僅在ORDER BY之前

10.1、聚合窗囗函數

  • 基本語法:
聚合函數(字段) over (partition by 字段 order by 字段)
聚合函數:COUNT SUM MIN MAX AVG
  • 案例
#查詢20200106充值的人ID以及總充值次數
select userId,count(userId) over () from game_charge_data where dt=20200106;

#查詢20200106充值的人ID以及總充值人數
select userId,count(1) over () from game_charge_data where dt=20200106 group by userId;

#查看每條充值記錄明細以及當前充值總額 partition by
select userId,chargetime,chargeSrc,chargeMoney,sum(chargeMoney) over (partition by dt ) from game_charge_data where dt=20200106

#窗口排序 order by
select userId,chargetime,chargeSrc,chargeMoney,count(1) over(),sum(chargeMoney) over (partition by dt order by chargetime asc) from game_charge_data where dt=20200106

注意:當同一個select查詢中存在多個窗口函數時,他們相互之間是沒有影響的.每個窗口函數應用自己的規則.

10.2、窗口規則

  • 規則子句
    • PRECEDING:往前
    • FOLLOWING:往後
    • CURRENT ROW:當前行
    • UNBOUNDED:起點
    • UNBOUNDED PRECEDING 表示從前面的起點
    • UNBOUNDED FOLLOWING:表示到後面的終點
  • 案例
select chargeTime,userId,chargeSrc,chargeMoney,
--所有行總充值
sum(chargeMoney) over() as sumCharge,
--每個userId的總充值
sum(chargeMoney) over(partition by userId) as
everyUserSumChargeMoeny,
--根據userId分組,並計算起點到當前行總充值
sum(chargeMoney) over(partition by userId order by chargeTime asc) as groupSumChargeMoeny,
--根據userId分組,並計算起點到當前行總充值
sum(chargeMoney) over(partition by userId order by chargeTime rows between UNBOUNDED PRECEDING and current row ) as groupSumChargeMoeny2,
--組內相鄰兩行充值數據之和
sum(chargeMoney) over(partition by userId order by chargeTime rows between 1 PRECEDING and current row) as towRowChargeMoney,
--組內相鄰三行的充值數據之和
sum(chargeMoney) over(partition by userId order by chargeTime rows between 1 PRECEDING AND 1 FOLLOWING ) as threeRowChargeMoney,
--組內從當前到最終充值總和
sum(chargeMoney) over(partition by userId order by chargeTime rows between current row and UNBOUNDED FOLLOWING ) as afterChargeMoney from game_charge_data where dt=20200106

10.3、排序窗口

  • 常用的三個排序函數
    • row_number() : 窗口內排序,從1開始順序排序
    • rank() :窗口內排序,從1開始,排名相等會在名次中留下空位
    • dense_rank() :窗口內排序,從1開始,排名相等不會在名次中留下空位
  • 案例
需求: 每天每人充值總數排名
with tmp as (select dt,userId,sum(chargeMoney) moneys from game_charge_data group by dt,userId)
select dt,userId,moneys,
row_number() over (partition by dt order by moneys desc) as r1,
rank() over (partition by dt order by moneys desc) r2,
dense_rank() over (partition by dt order by moneys desc) r3
from tmp

10.4、值窗囗函數

  • 值函數
    • first_value(x) over (partition by order by) :返回窗口內第一個值,x爲列名
    • last_value(x) over (partition by order by):返回窗口內最後一個值
    • lead(x,offset,defualtValue) over (partition by order by): 返回窗口內當前行後偏移offset值,當前行offset爲0,爲NULL則默認值
    • lag(x,offset,defualtValue) over (partition by order by):返回窗口內當前行往前偏移offset值,當前行offset爲0,爲NULL則默認值
  • 案例
#查詢用戶的所有登錄記錄,並且將其IP地址進行歸因(歸因到第一次登錄的IP地址)
select userId,loginIp,loginTime,first_value(loginIp) 
over (partition by userId order by loginTime asc) firstLoginIp 
from game_login_data 
where userName=670806772 
order by loginTime asc;

#根據第一步反過來調用,獲取最後一個值
select userId,loginIp,loginTime,last_value(loginIp) 
over (partition by userId order by loginTime asc) firstLoginIp 
from game_login_data 
where userName=670806772 
order by loginTime asc;

#查詢距離當前登錄時間的上一次登錄時間多少
select userId,loginIp,loginTime,lag(loginTime,1,1111) 
over (partition by userId order by loginTime asc) upLgoinTime 
from game_login_data
where userName=670806772 
order by loginTime asc;

#反過來 後續一次登錄時間
select userId,loginIp,loginTime,lead(loginTime,1,1111) 
over (partition by userId order by loginTime asc) afterLoginTime 
from game_login_data
where userName=670806772 
order by loginTime asc;

#計算每人兩次充值差值情況
with a as ( select dt,userId,chargemoney,lag(chargemoney,1,0) 
over (partition by userId order by dt desc) as last_money 
from game_charge_data 
where dt=20200106)
select dt,userId ,chargemoney,last_money,chargemoney- last_money chazhi
from a 
order by userId , dt

注意:如果只使用partition by子句,未指定order by的話,我們的聚合是分組內的聚合.
使用了order by子句,未使用window子句的情況下,默認從起點到當前行.

11、函數

11.1、系統內置函數

  • 查看系統內置函數
    hive> show functions;
  • 顯示內置函數用法
    hive> desc function upper;
  • 詳細顯示內置函數用法
    hive> desc function extended upper;

11.2自定義函數

1)Hive 自帶了一些函數,比如:max/min 等,但是數量有限,自己可以通過自定義 UDF來方便的擴展。

2)當 Hive 提供的內置函數無法滿足你的業務處理需要時,此時就可以考慮使用用戶自定義函數(UDF:user-defined function)。

3)根據用戶自定義函數類別分爲以下三種:

  • UDF(User-Defined-Function)
    一進一出
  • UDAF(User-Defined Aggregation Function)
    聚集函數,多進一出
    類似於:count/max/min
  • UDTF(User-Defined Table-Generating Functions)
    一進多出
    如 lateral view explore()

4)官方文檔地址:https://cwiki.apache.org/confluence/display/Hive/HivePlugins

5)編程步驟:

  • 繼承 org.apache.hadoop.hive.ql.UDF
  • 需要實現 evaluate 函數;evaluate 函數支持重載;
  • 在 hive 的命令行窗口創建函數
    • 添加 jar
      add jar linux_jar_path
    • 創建 function,
      create [temporary] function [dbname.]function_name AS class_name;
  • 在 hive 的命令行窗口刪除函數
    Drop [temporary] function [if exists] [dbname.]function_name;

6)注意事項

  • UDF 必須要有返回類型,可以返回 null,但是返回類型不能爲 void;

11.3、自定義UDF

操作步驟:

  • 創建maven工程
  • 導入pom文件
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
  • 創建函數類
import org.apache.hadoop.hive.ql.exec.UDF;
/**
* 將人民幣轉換成外幣
*/
public class Money extends UDF {
public double evaluate(final int s,final double rate) {
return s*rate;
}
}
  • 打jar包 並上傳至服務器
  • 將jar包添加到hive的classpath
add jar ${Path}
add jar /home/biubiubiu/udf-1.0-SNAPSHOT.jar;
  • 創建函數
create temporary function f_money as 'com.biubiubiu.function.Money';
  • 使用函數
select f_money(chargeMoney,0.6) from game_charge_data limit 1;
  • 注意:這種函數使用具有臨時性,只能保證當前會話可用
  • 永久生效
將jar 上傳到
hadoop fs -put /home/user/hive-functions.jar /user/hive/jars/hive-functions.jar
創建函數
create function f_money as 'com.biubiubiu.function.Money' using jar 'hdfs:/user/hive/jar/udf-1.0-SNAPSHOT.jar';

八、Hive企業及優化

  • Hive作爲數據管理和分析工具,處理數據的基本流程:通過元數據信息定位數據位置,解析SQL生成數據處理程序對數據進行處理,最終輸出數據結果。
  • 主要是:輸入、處理、輸出 三個階段,優化重點:輸入、處理
  • 優化配置參數:網址
    注意:優化之前,先修改日誌輸出級別。這樣可以能夠更好地查看日誌數據,幫助我們優化
  • hive.root.logger=DEBUG #設置成DEBUG級別
  • set 命令:查看hive當前所有配置信息

1、輸入數據優化

優化原則:儘量的減少輸入數據量

1.1、構建分區表和創建動態分區

  • 構建分區表
創建分區表
partitioned by(分區列 數據類型) 創建分區表
配置:
#開啓動態分區
set hive.exec.dynamic.partition=true
#設置動態分區模式
set hive.exec.dynamic.partition.mode=nonstrict|strict
(strict:嚴格模式下必須存在一個靜態分區,nonstrict; 非嚴格模式,所有分區都是動態的)
#允許創建動態分區最大數
set hive.exec.max.dynamic.partitions=1000
#在執行過程中每個MR能夠創建最大分區數
set hive.exec.max.dynamic.partitions.pernode=100
#當存在NULL分區時,是否允許拋出異常
set hive.error.on.empty.partition=false
注意:當分區字段爲NULL時,會創建默認分區
  • 構建分桶表
#創建分通表
clusted by (分區列) into 分桶個數 buckets;
#啓動分桶機制
set hive.enforce.bucketing=true
  • 在查詢的時候儘量使用分區或者分桶字段,這樣能夠有效的減少數據的導入

1.2、數據存儲優化

Hive支持行式存儲格式和列式存儲格式

  • 行式存儲格式:相關數據保存在一起,數據讀取的時候以行爲單位讀取的
    • 優點:這種存儲格式簡單、方便寫入數據 。
    • 缺點:不支持壓縮、並且不支持列裁剪,數據分析開銷較大
    • 文件格式:TextFile、SequenceFile
  • 列式存儲格式:將不同的列存放在不同的塊中。
    • 優點:支持列裁剪、減少數據查詢範圍,數據支持壓縮,節省空間。
    • 缺點:寫入數據相對困難,並且查詢整行數據時,開銷相對較大。
    • 文件格式:ORC、PARQUET、RCFILE

2、數據處理優化

2.1、數據處理引擎選擇

Hive支持多種數據處理引擎,MapReduce、Spark等

hive.execution.engine=mr|spark 默認是:mr
針對不同的引擎有不同的優化方案: 以下優化方案是基於mr引擎的

2.2、數據抓取

Fetch 抓取是指,Hive 中對某些情況的查詢可以不必使用 MapReduce 計算。
例如:
SELECT * FROM employees;在這種情況下,Hive 可以簡單地讀取 employee 對應的存儲目錄下的文件,然後輸出查詢結果到控制檯。

在 hive-default.xml.template 文件中 hive.fetch.task.conversion 默認是 more,老版本 hive默認是 minimal,該屬性修改爲 more 以後,在全局查找、字段查找、limit 查找等都不走mapreduce。

針對select * from 表這類操作可以不用啓動job,只需要對文件掃描讀取就可以

hive.fetch.task.conversion=none|minimal|more 默認值:more
none:任何查詢都會啓動job任務
select * from game_login_data limit 1; #會啓動job任務
minimal:針對select filter、limitwherehaving 不會啓動job,針對udf會啓動job任務
select substring(userId,0,2) from game_login_data limit 1; #會啓動定時任務
more: 能夠最大限度的避免啓動job
select substring(userId,0,2) from game_login_data limit 1 #不會啓動定時任務

2.3、本地模式

大多數的 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;
  • 針對針對少量數據,是完全沒有必要通過集羣進行數據處理的,因爲觸發job任務啓動的時候很可能大於數據處理時間,針對這種情況可以考慮採用本地模式,通過單節點處理數據
hive.exec.mode.local.auto=false|ture #默認是false
操作案例:
set hive.exec.mode.local.auto=false;
select userId,count(1) from game_login_data where dt=20200106 group by userId limit 1;
耗時:20秒鐘時間
set hive.exec.mode.local.auto=true;
select userId,count(1) from game_login_data where dt=20200106 group by userId limit 1;
耗時:1秒鐘時間
  • 如何界定少量的數據,文件個數和任務數
hive.exec.mode.local.auto.inputbytes.max=134217728 默認值:128M
hive.exec.mode.local .auto.input.files.max=4 默認最大值4
hive.exec.mode.local.auto.tasks.max=4 默認最大任務數

2.4、數據處理的並行度

在一個job任務中可以指定reduce的相關參數,增加數據處理效率

mapred.reduce.tasks=-1 #默認-1 此時hive將自動計算reduce個數。
#reduce的個數的多少是由reduce處理的數據量大小決定的
#設置每個reduce處理的數據量大小
hive.exec.reducers.bytes.per.reducer=256,000,000 #默認256M

2.5、聚合操作優化

Hive本質是MR操作,所以優化操作也需要分爲兩個階段:Map階段和Reduce階段

2.5.1、group by優化

group by 分組操作,其可以在map端先進行聚合,在reduce階段在進行聚合

#開啓map端聚合,減少reduce階段數據量
hive.map.aggr=true
#有數據傾斜的時候進行負載均衡
hive.groupby.skewindata=true|false(默認false)
#此時以爲這會啓動兩個MRjob任務,第一個MRjob任務會將key隨機分佈到不同的
reduce,並將中間結果數據輸出到,第二個任務MRjob會將相同的key分發的同一reduce進行聚合操作
#如何節點某個key是否傾斜,當一個key查過10萬的時,則認定數據存在傾斜行爲,此時會對該key進行拆分,通過兩個MRJob進行聚合操作
hive.groupby.mapaggr.checkinterval=100000 默認值10
2.5.2、count distinct優化

去重統計:該操作僅需要一個Reduce Task完成去重複,數據量過大會造成Job執行時間過程,甚至OOM風險。解決方案是:COUNT DISTINCT優先使用GROUP BY再COUNT的方式替換

此時啓動1個job任務
select count(distinct userId) from game_login_data;
此時會啓動多個job任務,配合group by 優化參數
select count(userId) from (select userId from game_login_data group by userId) a;

2.6、join優化

join 兩個表或者多個表關聯操作,兩種情況:

  • 小表 join 大表:小表數據量小於1000,此時可以先將小表緩存,在map端進行聚合操作
配置參數:
hive.mapjoin.smalltable.filesize=25000000 默認:25M
#開啓map端聚合
hive.auto.convert.join = true;
#構建兩個臨時表 一個大表一個小表
create temporary table big_data(roleId int);
load data local inpath '/home/tzb/data/big_data' into table big_data;
#小表
create temporary table small_data(roleId int,roleName string) row format delimited fields terminated by '\t';
#導入數據
load data local inpath '/home/tzb/data/small_data' into table small_data;
#join操作
#開啓和關閉map端聚合
set hive.auto.convert.join = false;
select b.roleId,a.roleName from big_data b 
left join small_data s on b.roleId=s.roleId limit 10;
最好的優化方案
select b.roleId,s.roleName from (select * from big_data limit 10) b
left join small_data s on b.roleId=s.roleId;
結論:開啓map端聚合能夠大大提高執行效率
  • 大表 join 大表
    • 儘量通過子查詢 減少大表的數據量
    • 通過聚合函數,減少大表的數據量
    • 避免無效的關聯操作

2.7、數據傾斜優化

2.7.1、合理設置map數
mapred.min.split.size: 指的是數據的最小分割單元大小;min的默認值是1B
mapred.max.split.size: 指的是數據的最大分割單元大小;max的默認值是256MB
# 通過調整max可以起到調整map數的作用,減小max可以增加map數,增大max可以減少map數。
# 需要提醒的是,直接調整mapred.map.tasks這個參數是沒有效果的。
  1. 通常情況下,作業會通過 input 的目錄產生一個或者多個 map 任務。
    主要的決定因素有:input 的文件總個數,input 的文件大小,集羣設置的文件塊大小。
  2. 是不是 map 數越多越好?
    答案是否定的。如果一個任務有很多小文件(遠遠小於塊大小 128m),則每個小文件也會被當做一個塊,用一個 map 任務來完成,而一個 map 任務啓動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費。而且,同時可執行的 map 數是受限的。
  3. 是不是保證每個 map 處理接近 128m 的文件塊,就高枕無憂了?
    答案也是不一定。比如有一個 127m 的文件,正常會用一個 map 去完成,但這個文件只有一個或者兩個小字段,卻有幾千萬的記錄,如果 map 處理的邏輯比較複雜,用一個 map任務去做,肯定也比較耗時。

針對上面的問題 2 和 3,我們需要採取兩種方式來解決:即減少 map 數和增加 map 數

2.7.2、合理設置reduce個數
hive.exec.reducers.bytes.per.reducer(每個reduce任務處理的數據量,默認爲1000^3=1G)
hive.exec.reducers.max(每個任務最大的reduce數,默認爲999

1.調整 reduce 個數方法一

  • 每個 Reduce 處理的數據量默認是 256MB
    hive.exec.reducers.bytes.per.reducer=256000000
  • 每個任務最大的 reduce 數,默認爲 1009
    hive.exec.reducers.max=1009
  • 計算 reducer 數的公式
    N=min(參數 2,總輸入數據量/參數 1)

2.調整 reduce 個數方法二
在 hadoop 的 mapred-default.xml 文件中修改

# 設置每個 job 的 Reduce 個數
set mapreduce.job.reduces = 15;

3.reduce 個數並不是越多越好

  • 過多的啓動和初始化 reduce 也會消耗時間和資源;
  • 另外,有多少個 reduce,就會有多少個輸出文件,如果生成了很多個小文件,那麼如果這些小文件作爲下一個任務的輸入,則也會出現小文件過多的問題;

在設置 reduce 個數的時候也需要考慮這兩個原則:

  1. 處理大數據量利用合適的 reduce 數;
  2. 使單個 reduce 任務處理數據量大小要合適;
2.7.3、合併小文件

在 map 執行前合併小文件,減少 map 數:CombineHiveInputFormat 具有對小文件進行合併的功能(系統默認的格式)。HiveInputFormat 沒有對小文件合併功能。
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

是否合併Map輸出文件:hive.merge.mapfiles=true(默認值爲true)
是否合併Reduce端輸出文件:hive.merge.mapredfiles=false(默認值爲false)
合併文件的大小:hive.merge.size.per.task=256*1000*1000(默認值爲256000000
2.7.4、複雜文件增加 Map 數

當 input 的文件都很大,任務邏輯複雜,map 執行非常慢的時候,可以考慮增加 Map數,來使得每個 map 處理的數據量減少,從而提高任務的執行效率。

增加 map 的方法爲:根據computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M 公式,調整 maxSize 最大值。讓 maxSize 最大值低於 blocksize 就可以增加 map 的個數。

2.8、設置並行執行

Hive 會將一個查詢轉化成一個或者多個階段。這樣的階段可以是 MapReduce 階段、抽樣階段、合併階段、limit 階段。或者 Hive 執行過程中可能需要的其他階段。默認情況下,Hive 一次只會執行一個階段。不過,某個特定的 job 可能包含衆多的階段,而這些階段可能並非完全互相依賴的,也就是說有些階段是可以並行執行的,這樣可能使得整個 job 的執行時間縮短。不過,如果有更多的階段可以並行執行,那麼 job 可能就越快完成。

通過設置參數 hive.exec.parallel 值爲 true,就可以開啓併發執行。不過,在共享集羣中,需要注意下,如果 job 中並行階段增多,那麼集羣利用率就會增加。

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

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

2.9、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數量
mapreduce.job.jvm.numtasks=10

這個功能的缺點是,開啓 JVM 重用將一直佔用使用到的 task 插槽,以便進行重用,直到任務完成後才能釋放。如果某個“不平衡的”job 中有某幾個 reduce task 執行的時間要比其他 Reduce task 消耗的時間多的多的話,那麼保留的插槽就會一直空閒着卻無法被其他的 job使用,直到所有的 task 都結束了纔會釋放。

2.10、推測執行

在分佈式集羣環境下,因爲程序 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>
#開啓mapreduce的推測機制
mapreduce.map.speculative=true

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

3、壓縮

輸入、輸出數據的壓縮都可以有效調優。具體見上邊壓縮方式。

覺得有幫助的,請多多支持博主,點贊關注哦~

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