第一章、數據定義語言(DDL)概述
1.1 DDL語法的作用
數據定義語言 (Data Definition Language, DDL),是SQL語言集中對數據庫內部的對象結構進行創建,刪除,修改等的操作語言,這些數據庫對象包括database(schema)、table、view、index等。核心語法由CREATE、ALTER與DROP三個所組成。DDL並不涉及表內部數據的操作。
在某些上下文中,該術語也稱爲數據描述語言,因爲它描述了數據庫表中的字段和記錄。
1.2 Hive中DDL使用
Hive SQL(HQL)與SQL的語法大同小異,基本上是相通的,學過SQL的使用者可以無痛使用Hive SQL。只不過在學習HQL語法的時候,特別要注意Hive自己特有的語法知識點,比如partition相關的DDL操作。
基於Hive的設計、使用特點,HQL中create語法(尤其create table)將是學習掌握DDL語法的重中之重。可以說建表是否成功直接影響數據文件是否映射成功,進而影響後續是否可以基於SQL分析數據。通俗點說,沒有表,表沒有數據,你分析什麼呢?
選擇正確的方向,往往比盲目努力重要。
第二章、Hive DDL建表基礎
2.1 完整建表語法樹
- 藍色字體是建表語法的關鍵字,用於指定某些功能。
- []中括號的語法表示可選。
- |表示使用的時候,左右語法二選一。
- 建表語句中的語法順序要和上述語法規則保持一致。
2.2 Hive數據類型詳解
整體概述
Hive中的數據類型指的是Hive表中的列字段類型。Hive數據類型整體分爲兩個類別:原生數據類型(primitive data type)和複雜數據類型(complex data type)。
原生數據類型包括:數值類型、時間類型、字符串類型、雜項數據類型;
複雜數據類型包括:array數組、map映射、struct結構、union聯合體。
關於Hive的數據類型,需要注意:
- 英文字母大小寫不敏感;
- 除SQL數據類型外,還支持Java數據類型,比如:string;
- int和string是使用最多的,大多數函數都支持;
- 複雜數據類型的使用通常需要和分隔符指定語法配合使用。
- 如果定義的數據類型和文件不一致,hive會嘗試隱式轉換,但是不保證成功。
原生數據類型
Hive支持的原生數據類型如下圖所示:
其中標註的數據類型是使用較多的,詳細的描述請查詢語法手冊:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types
複雜數據類型
Hive支持的複雜數據類型如下圖所示:
其中標註的數據類型是使用較多的,詳細的描述請查詢語法手冊:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types
數據類型隱式、顯示轉換
與SQL類似,HQL支持隱式和顯式類型轉換。
原生類型從窄類型到寬類型的轉換稱爲隱式轉換,反之,則不允許。
下表描述了類型之間允許的隱式轉換:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types
顯式類型轉換使用CAST函數。
例如,CAST('100'as INT)會將100字符串轉換爲100整數值。 如果強制轉換失敗,例如CAST('INT'as INT),該函數返回NULL。
2.3 Hive讀寫文件機制
SerDe是什麼
SerDe是Serializer、Deserializer的簡稱,目的是用於序列化和反序列化。序列化是對象轉化爲字節碼的過程;而反序列化是字節碼轉換爲對象的過程。
Hive使用SerDe(和FileFormat)讀取和寫入行對象。
需要注意的是,“key”部分在讀取時會被忽略,而在寫入時key始終是常數。基本上行對象存儲在“value”中。
可以通過desc formatted tablename查看錶的相關SerDe信息。默認如下:
Hive讀寫文件流程
Hive讀取文件機制:首先調用InputFormat(默認TextInputFormat),返回一條一條kv鍵值對記錄(默認是一行對應一條記錄)。然後調用SerDe(默認LazySimpleSerDe)的Deserializer,將一條記錄中的value根據分隔符切分爲各個字段。
Hive寫文件機制:將Row寫入文件時,首先調用SerDe(默認LazySimpleSerDe)的Serializer將對象轉換成字節序列,然後調用OutputFormat將數據寫入HDFS文件中。
SerDe相關語法
在Hive的建表語句中,和SerDe相關的語法爲:
其中ROW FORMAT是語法關鍵字,DELIMITED和SERDE二選其一。
如果使用delimited表示使用默認的LazySimpleSerDe類來處理數據。如果數據文件格式比較特殊可以使用ROW FORMAT SERDE serde_name指定其他的Serde類來處理數據,甚至支持用戶自定義SerDe類。
LazySimpleSerDe分隔符指定
LazySimpleSerDe是Hive默認的序列化類,包含4種子語法,分別用於指定字段之間、集合元素之間、map映射 kv之間、換行的分隔符號。在建表的時候可以根據數據的特點靈活搭配使用。
默認分隔符
hive建表時如果沒有row format語法。此時字段之間默認的分割符是'\001',是一種特殊的字符,使用的是ascii編碼的值,鍵盤是打不出來的。
在vim編輯器中,連續按下Ctrl+v/Ctrl+a即可輸入'\001' ,顯示^A
在一些文本編輯器中將以SOH的形式顯示:
2.4 Hive數據存儲路徑
默認存儲路徑
Hive表默認存儲路徑是由${HIVE_HOME}/conf/hive-site.xml配置文件的hive.metastore.warehouse.dir屬性指定。默認值是:/user/hive/warehouse。
在該路徑下,文件將根據所屬的庫、表,有規律的存儲在對應的文件夾下。
指定存儲路徑
在Hive建表的時候,可以通過location語法來更改數據在HDFS上的存儲路徑,使得建表加載數據更加靈活方便。
語法:LOCATION '<hdfs_location>'。
對於已經生成好的數據文件,使用location指定路徑將會很方便。
3.5 案例—王者榮耀
原生數據類型案例
文件archer.txt中記錄了手遊《王者榮耀》射手的相關信息,內容如下所示,其中字段之間分隔符爲製表符\t,要求在Hive中建表映射成功該文件。
1 后羿 5986 1784 396 336 remotely archer 2 馬可波羅 5584 200 362 344 remotely archer 3 魯班七號 5989 1756 400 323 remotely archer 4 李元芳 5725 1770 396 340 remotely archer 5 孫尚香 6014 1756 411 346 remotely archer 6 黃忠 5898 1784 403 319 remotely archer 7 狄仁傑 5710 1770 376 338 remotely archer 8 虞姬 5669 1770 407 329 remotely archer 9 成吉思汗 5799 1742 394 329 remotely archer 10 百里守約 5611 1784 410 329 remotely archer
字段含義:id、name(英雄名稱)、hp_max(最大生命)、mp_max(最大法力)、attack_max(最高物攻)、defense_max(最大物防)、attack_range(攻擊範圍)、role_main(主要定位)、role_assist(次要定位)。
分析一下:字段都是基本類型,字段的順序需要注意一下。字段之間的分隔符是製表符,需要使用row format語法進行指定。
建表語句:
--創建數據庫並切換使用 create database itcast; use itcast; --ddl create table create table t_archer( id int comment "ID", name string comment "英雄名稱", hp_max int comment "最大生命", mp_max int comment "最大法力", attack_max int comment "最高物攻", defense_max int comment "最大物防", attack_range string comment "攻擊範圍", role_main string comment "主要定位", role_assist string comment "次要定位" ) comment "王者榮耀射手信息" row format delimited fields terminated by "\t";
建表成功之後,在Hive的默認存儲路徑下就生成了表對應的文件夾,把archer.txt文件上傳到對應的表文件夾下。
hadoop fs -put archer.txt /user/hive/warehouse/honor_of_kings.db/t_archer
執行查詢操作,可以看出數據已經映射成功。
想一想:Hive這種能力是不是比mysql一條一條insert插入數據方便多了?
複雜數據類型案例
文件hot_hero_skin_price.txt中記錄了手遊《王者榮耀》熱門英雄的相關皮膚價格信息,內容如下,要求在Hive中建表映射成功該文件。
1,孫悟空,53,西部大鏢客:288-大聖娶親:888-全息碎片:0-至尊寶:888-地獄火:1688 2,魯班七號,54,木偶奇遇記:288-福祿兄弟:288-黑桃隊長:60-電玩小子:2288-星空夢想:0 3,後裔,53,精靈王:288-阿爾法小隊:588-輝光之辰:888-黃金射手座:1688-如夢令:1314 4,鎧,52,龍域領主:288-曙光守護者:1776 5,韓信,52,飛衡:1788-逐夢之影:888-白龍吟:1188-教廷特使:0-街頭霸王:888
字段:id、name(英雄名稱)、win_rate(勝率)、skin_price(皮膚及價格)
分析一下:前3個字段原生數據類型、最後一個字段複雜類型map。需要指定字段之間分隔符、集合元素之間分隔符、map kv之間分隔符。
建表語句:
create table t_hot_hero_skin_price( id int, name string, win_rate int, skin_price map<string,int> )row format delimited fields terminated by ',' --指定字段之間分隔符 collection items terminated by '-' --指定集合元素之間的分隔符 map keys terminated by ':' ;---指定map元素kv之間的分隔符
建表成功後,把hot_hero_skin_price.txt文件上傳到對應的表文件夾下。
hadoop fs -put hot_hero_skin_price.txt /user/hive/warehouse/honor_of_kings.db/t_hot_hero_skin_price
執行查詢操作,可以看出數據已經映射成功。
想一想:如果最後一個字段以String類型來定義,後續使用方便嗎?
默認分隔符案例
文件team_ace_player.txt中記錄了手遊《王者榮耀》主要戰隊內最受歡迎的王牌選手信息,內容如下,要求在Hive中建表映射成功該文件。
字段:id、team_name(戰隊名稱)、ace_player_name(王牌選手名字)
分析一下:數據都是原生數據類型,且字段之間分隔符是\001,因此在建表的時候可以省去row format語句,因爲hive默認的分隔符就是\001。
建表語句:
create table t_team_ace_player( id int, team_name string, ace_player_name string ); --沒有指定row format語句 此時採用的是默認的\001作爲字段的分隔符
建表成功後,把team_ace_player.txt文件上傳到對應的表文件夾下。
hadoop fs -put team_ace_player.txt /user/hive/warehouse/honor_of_kings.db/t_team_ace_player
執行查詢操作,可以看出數據已經映射成功。
想一想:字段以\001分隔建表時很方便,那麼採集、清洗數據時對數據格式追求有什麼啓發?你青睞於什麼分隔符?
優先考慮\001分隔符
指定數據存儲路徑
文件team_ace_player.txt中記錄了手遊《王者榮耀》主要戰隊內最受歡迎的王牌選手信息,字段之間使用的是\001作爲分隔符。
要求把文件上傳到HDFS任意路徑下,不能移動複製,並在Hive中建表映射成功該文件。
建表語句
create table t_team_ace_player( id int, team_name string, ace_player_name string )location '/tmp';--使用location關鍵字指定本張表數據在hdfs上的存儲路徑
第三章、Hive DDL建表高階
3.1 Hive內、外部表
內部表
內部表(Internal table)也稱爲被Hive擁有和管理的託管表(Managed table)。默認情況下創建的表就是內部表,Hive擁有該表的結構和文件。換句話說,Hive完全管理表(元數據和數據)的生命週期,類似於RDBMS(關係型數據庫)中的表。
當您刪除內部表時,它會刪除數據以及表的元數據。
create table student( num int, name string, sex string, age int, dept string) row format delimited fields terminated by ',';
可以使用DESCRIBE FORMATTED itcast.student;來獲取表的描述信息,從中可以看出表的類型。
外部表
外部表(External table)中的數據不是Hive擁有或管理的,只管理表元數據的生命週期。要創建一個外部表,需要使用EXTERNAL語法關鍵字。
刪除外部表只會刪除元數據,而不會刪除實際數據。在Hive外部仍然可以訪問實際數據。
而且外部表更爲方便的是可以搭配location語法指定數據的路徑。
create external table student_ext( num int, name string, sex string, age int, dept string) row format delimited fields terminated by ',' location '/stu';
可以使用DESC FORMATTED itcast. student_ext;來獲取表的描述信息,從中可以看出表的類型。
內部表、外部表差異
無論內部表還是外部表,Hive都在Hive Metastore中管理表定義及其分區信息。
- 刪除內部表會從Metastore中刪除表元數據,還會從HDFS中刪除其所有數據/文件。
- 刪除外部表,只會從Metastore中刪除表的元數據,並保持HDFS位置中的實際數據不變。
如何選擇內部表、外部表
當需要通過Hive完全管理控制表的整個生命週期時,請使用內部表。
當文件已經存在或位於遠程位置時,請使用外部表,因爲即使刪除表,文件也會被保留。
Location關鍵字
- 在創建外部表的時候,可以使用location指定存儲位置路徑,如果不指定會如何?
如果不指定location,外部表的默認路徑也是位於/user/hive/warehouse,由默認參數控制。
- 創建內部表的時候,是否可以使用location指定?
內部表可以使用location指定位置的。
- 是否意味着Hive表的數據在HDFS上的位置不是一定要在/user/hive/warehouse下?
不一定,Hive中表數據存儲位置,不管內部表還是外部表,默認都是在/user/hive/warehouse,當然可以在建表的時候通過location關鍵字指定存儲位置在HDFS的任意路徑。
3.2 Hive分區表
2.1.分區表的引入、產生背景
現有6份數據文件,分別記錄了《王者榮耀》中6種位置的英雄相關信息。現要求通過建立一張表t_all_hero,把6份文件同時映射加載。
create table t_all_hero( id int, name string, hp_max int, mp_max int, attack_max int, defense_max int, attack_range string, role_main string, role_assist string ) row format delimited fields terminated by "\t";
加載數據文件到HDFS指定路徑下:
hadoop fs -put archer.txt assassin.txt mage.txt support.txt tank.txt warrior.txt /user/hive/warehouse/itcast.db/t_all_hero
現要求查詢role_main主要定位是射手並且hp_max最大生命大於6000的有幾個,sql語句如下:
select count(*) from t_all_hero where role_main="archer" and hp_max >6000;
思考一下:where語句的背後需要進行全表掃描才能過濾出結果,對於hive來說需要掃描表下面的每一個文件。如果數據文件特別多的話,效率很慢也沒必要。本需求中,只需要掃描archer.txt文件即可,如何優化可以加快查詢,減少全表掃描呢?
分區表的概念、創建
當Hive表對應的數據量大、文件多時,爲了避免查詢時全表掃描數據,Hive支持根據用戶指定的字段進行分區,分區的字段可以是日期、地域、種類等具有標識意義的字段。比如把一整年的數據根據月份劃分12個月(12個分區),後續就可以查詢指定月份分區的數據,儘可能避免了全表掃描查詢。
分區表建表語法:
CREATE TABLE table_name (column1 data_type, column2 data_type) PARTITIONED BY (partition1 data_type, partition2 data_type,….);
針對《王者榮耀》英雄數據,重新創建一張分區表t_all_hero_part,以role角色作爲分區字段。
create table t_all_hero_part( id int, name string, hp_max int, mp_max int, attack_max int, defense_max int, attack_range string, role_main string, role_assist string ) partitioned by (role string) row format delimited fields terminated by "\t";
需要注意:分區字段不能是表中已經存在的字段,因爲分區字段最終也會以虛擬字段的形式顯示在表結構上。
分區表數據加載--靜態分區
所謂靜態分區指的是分區的字段值是由用戶在加載數據的時候手動指定的。
語法如下:
load data [local] inpath ' ' into table tablename partition(分區字段='分區值'...);
Local表示數據是位於本地文件系統還是HDFS文件系統。關於load語句後續詳細展開講解。
靜態加載數據操作如下,文件都位於Hive服務器所在機器本地文件系統上。
load data local inpath '/opt/module/hive/archer.txt' into table t_all_hero_part partition(role='sheshou'); load data local inpath '/opt/module/hive/assassin.txt' into table t_all_hero_part partition(role='cike'); load data local inpath '/opt/module/hive/mage.txt' into table t_all_hero_part partition(role='fashi'); load data local inpath '/opt/module/hive/support.txt' into table t_all_hero_part partition(role='fuzhu'); load data local inpath '/opt/module/hive/tank.txt' into table t_all_hero_part partition(role='tanke'); load data local inpath '/opt/module/hive/warrior.txt' into table t_all_hero_part partition(role='zhanshi');
分區掃描:
select count(*) from t_all_hero_part where role="archer" and hp_max >6000
分區表數據加載--動態分區
往hive分區表中插入加載數據時,如果需要創建的分區很多,則需要複製粘貼修改很多sql去執行,效率低。因爲hive是批處理系統,所以hive提供了一個動態分區功能,其可以基於查詢參數的位置去推斷分區的名稱,從而建立分區。
所謂動態分區指的是分區的字段值是基於查詢結果自動推斷出來的。核心語法就是insert+select。
啓用hive動態分區,需要在hive會話中設置兩個參數:
set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict;
第一個參數表示開啓動態分區功能,第二個參數指定動態分區的模式。分爲nonstick非嚴格模式和strict嚴格模式。strict嚴格模式要求至少有一個分區爲靜態分區。
創建一張新的分區表t_all_hero_part_dynamic
create table t_all_hero_part_dynamic( id int, name string, hp_max int, mp_max int, attack_max int, defense_max int, attack_range string, role_main string, role_assist string ) partitioned by (role string) row format delimited fields terminated by "\t";
執行動態分區插入(從原有的t_all_hero表中導入)
insert into table t_all_hero_part_dynamic partition(role) --注意這裏 分區值並沒有手動寫死指定 select tmp.*,tmp.role_main from t_all_hero tmp;
動態分區插入時,分區值是根據查詢返回字段位置自動推斷的。
select * from t_all_hero_part_dynamic;
分區表的本質
外表上看起來分區表好像沒多大變化,只不過多了一個分區字段。實際上在底層管理數據的方式發生了改變。這裏直接去HDFS查看區別。
非分區表:t_all_hero
分區表:t_all_hero_part
分區的概念提供了一種將Hive表數據分離爲多個文件/目錄的方法。不同分區對應着不同的文件夾,同一分區的數據存儲在同一個文件夾下。只需要根據分區值找到對應的文件夾,掃描本分區下的文件即可,避免全表數據掃描。
分區表的使用
分區表的使用重點在於:
一、建表時根據業務場景設置合適的分區字段。比如日期、地域、類別等;
二、查詢的時候儘量先使用where進行分區過濾,查詢指定分區的數據,避免全表掃描。
比如:查詢英雄主要定位是射手並且最大生命大於6000的個數。使用分區表查詢和使用非分區表進行查詢,SQL如下:
--非分區表 全表掃描過濾查詢 select count(*) from t_all_hero where role_main="archer" and hp_max >6000; --分區表 先基於分區過濾 再查詢 select count(*) from t_all_hero_part where role="sheshou" and hp_max >6000;
想一想:底層執行性能來說,分區表的優勢在哪裏?
分區表的注意事項
一、分區表不是建表的必要語法規則,是一種優化手段表,可選;
二、分區字段不能是表中已有的字段,不能重複;
三、分區字段是虛擬字段,其數據並不存儲在底層的文件中;
四、分區字段值的確定來自於用戶價值數據手動指定(靜態分區)或者根據查詢結果位置自動推斷(動態分區)
五、Hive支持多重分區,也就是說在分區的基礎上繼續分區,劃分更加細粒度
多重分區表
通過建表語句中關於分區的相關語法可以發現,Hive支持多個分區字段:PARTITIONED BY (partition1 data_type, partition2 data_type,….)。
多重分區下,分區之間是一種遞進關係,可以理解爲在前一個分區的基礎上繼續分區。從HDFS的角度來看就是文件夾下繼續劃分子文件夾。比如:把全國人口數據首先根據省進行分區,然後根據市進行劃分,如果你需要甚至可以繼續根據區縣再劃分,此時就是3分區表。
--單分區表,按省份分區 create table t_user_province (id int, name string,age int) partitioned by (province string); --雙分區表,按省份和市分區 create table t_user_province_city (id int, name string,age int) partitioned by (province string, city string); --三分區表,按省份、市、縣分區 create table t_user_province_city_county (id int, name string,age int) partitioned by (province string, city string,county string);
多分區表的數據插入和查詢使用
load data local inpath '文件路徑' into table t_user_province partition(province='shanghai'); load data local inpath '文件路徑' into table t_user_province_city_county partition(province='zhejiang',city='hangzhou',county='xiaoshan'); select * from t_user_province_city_county where province='zhejiang' and city='hangzhou';
3.3 Hive分桶表
分桶表的概念
分桶表也叫做桶表,源自建表語法中bucket單詞。是一種用於優化查詢而設計的表類型。該功能可以讓數據分解爲若干個部分易於管理。
在分桶時,我們要指定根據哪個字段將數據分爲幾桶(幾個部分)。
默認規則是:
可以發現桶編號相同的數據會被分到同一個桶當中。hash_function取決於分桶字段bucketing_column的類型:
如果是int類型,hash_function(int) == int;
如果是其他類型,比如bigint,string或者複雜數據類型,hash_function比較棘手,將是從該類型派生的某個數字,比如hashcode值。
分桶表的語法
--分桶表建表語句 CREATE [EXTERNAL] TABLE [db_name.]table_name [(col_name data_type, ...)] CLUSTERED BY (col_name) INTO N BUCKETS;
其中CLUSTERED BY (col_name)表示根據哪個字段進行分;
INTO N BUCKETS表示分爲幾桶(也就是幾個部分)。
需要注意的是,分桶的字段必須是表中已經存在的字段。
分桶表的創建
現有美國2021-1-28號,各個縣county的新冠疫情累計案例信息,包括確診病例和死亡病例,數據格式如下所示:
2021-01-28,Juneau City and Borough,Alaska,02110,1108,3 2021-01-28,Kenai Peninsula Borough,Alaska,02122,3866,18 2021-01-28,Ketchikan Gateway Borough,Alaska,02130,272,1 2021-01-28,Kodiak Island Borough,Alaska,02150,1021,5 2021-01-28,Kusilvak Census Area,Alaska,02158,1099,3 2021-01-28,Lake and Peninsula Borough,Alaska,02164,5,0 2021-01-28,Matanuska-Susitna Borough,Alaska,02170,7406,27 2021-01-28,Nome Census Area,Alaska,02180,307,0 2021-01-28,North Slope Borough,Alaska,02185,973,3 2021-01-28,Northwest Arctic Borough,Alaska,02188,567,1 2021-01-28,Petersburg Borough,Alaska,02195,43,0
字段含義如下:count_date(統計日期),county(縣),state(州),fips(縣編碼code),cases(累計確診病例),deaths(累計死亡病例)。
根據state州把數據分爲5桶,建表語句如下:
CREATE TABLE itcast.t_usa_covid19( count_date string, county string, state string, fips int, cases int, deaths int) CLUSTERED BY(state) INTO 5 BUCKETS;
在創建分桶表時,還可以指定分桶內的數據排序規則
--根據state州分爲5桶 每個桶內根據cases確診病例數倒序排序
CREATE TABLE itcast.t_usa_covid19_bucket_sort( count_date string, county string, state string, fips int, cases int, deaths int) CLUSTERED BY(state) sorted by (cases desc) INTO 5 BUCKETS;
分桶表的數據加載
--step1:開啓分桶的功能 從Hive2.0開始不再需要設置 set hive.enforce.bucketing=true; --step2:把源數據加載到普通hive表中 CREATE TABLE itcast.t_usa_covid19( count_date string, county string, state string, fips int, cases int, deaths int) row format delimited fields terminated by ","; --將源數據上傳到HDFS,t_usa_covid19表對應的路徑下 hadoop fs -put us-covid19-counties.dat /user/hive/warehouse/itcast.db/t_usa_covid19 --step3:使用insert+select語法將數據加載到分桶表中 insert into t_usa_covid19_bucket select * from t_usa_covid19;
到HDFS上查看t_usa_covid19_bucket底層數據結構可以發現,數據被分爲了5個部分。
並且從結果可以發現,只要hash_function(bucketing_column)一樣的,就一定被分到同一個桶中。
分桶表的使用好處
和非分桶表相比,分桶表的使用好處有以下幾點:
1、基於分桶字段查詢時,減少全表掃描
--基於分桶字段state查詢來自於New York州的數據 --不再需要進行全表掃描過濾 --根據分桶的規則hash_function(New York) mod 5計算出分桶編號 --查詢指定分桶裏面的數據 就可以找出結果 此時是分桶掃描而不是全表掃描 select * from t_usa_covid19_bucket where state="New York";
2、JOIN時可以提高MR程序效率,減少笛卡爾積數量
對於JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了分桶操作。那麼將保存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的數據量。
3、分桶表數據進行抽樣
當數據量特別大時,對全體數據進行處理存在困難時,抽樣就顯得尤其重要了。抽樣可以從被抽取的數據中估計和推斷出整體的特性,是科學實驗、質量檢驗、社會調查普遍採用的一種經濟有效的工作和研究方法。
3.4 Hive Transactional Tables事務表
Hive事務背景知識
Hive本身從設計之初時,就是不支持事務的,因爲Hive的核心目標是將已經存在的結構化數據文件映射成爲表,然後提供基於表的SQL分析處理,是一款面向分析的工具。且映射的數據通常存儲於HDFS上,而HDFS是不支持隨機修改文件數據的。
這個定位就意味着在早期的Hive的SQL語法中是沒有update,delete操作的,也就沒有所謂的事務支持了,因爲都是select查詢分析操作。
從Hive0.14版本開始,具有ACID語義的事務已添加到Hive中,以解決以下場景下遇到的問題:
- 流式傳輸數據。使用如Apache Flume或Apache Kafka之類的工具將數據流式傳輸到Hadoop集羣中。雖然這些工具可以每秒數百行或更多行的速度寫入數據,但是Hive只能每隔15分鐘到一個小時添加一次分區。頻繁添加分區會很快導致表中大量的分區。因此通常使用這些工具將數據流式傳輸到現有分區中,但是這會使讀者感到髒讀(也就是說,他們將在開始查詢後看到寫入的數據),並將許多小文件留在目錄中,這將給NameNode帶來壓力。通過事務功能,同時允許讀者獲得一致的數據視圖並避免過多的文件。
- 尺寸變化緩慢。在典型的星型模式數據倉庫中,維度表隨時間緩慢變化。例如,零售商將開設新商店,需要將其添加到商店表中,或者現有商店可能會更改其平方英尺或某些其他跟蹤的特徵。這些更改導致插入單個記錄或更新 記錄(取決於所選策略)。
- 數據重述。有時發現收集的數據不正確,需要更正。從Hive 0.14開始,可以通過INSERT,UPDATE和 DELETE支持這些用例 。
Hive事務表侷限性
雖然Hive支持了具有ACID語義的事務,但是在使用起來,並沒有像在MySQL中使用那樣方便,有很多侷限性。原因很簡單,畢竟Hive的設計目標不是爲了支持事務操作,而是支持分析操作,且最終基於HDFS的底層存儲機制使得文件的增加刪除修改操作需要動一些小心思。具體限制如下:
- 尚不支持BEGIN,COMMIT和ROLLBACK。所有語言操作都是自動提交的。
- 僅支持ORC文件格式(STORED AS ORC)。
- 默認情況下事務配置爲關閉。需要配置參數開啓使用。
- 表必須是分桶表(Bucketed)纔可以使用事務功能。
- 表參數transactional必須爲true;
- 外部表不能成爲ACID表,不允許從非ACID會話讀取/寫入ACID表。
案例:創建使用Hive事務表
如果不做任何配置修改,直接針對Hive中已有的表進行Update、Delete、Insert操作,可以發現,只有insert語句可以執行,Update和Delete操作會報錯。
Insert插入操作能夠成功的原因在於,底層是直接把數據寫在一個新的文件中的。
下面看一下如何在Hive中配置開啓事務表,並且進行操作
--Hive中事務表的創建使用 --1、開啓事務配置(可以使用set設置當前session生效 也可以配置在hive-site.xml中) set hive.support.concurrency = true; --Hive是否支持併發 set hive.enforce.bucketing = true; --從Hive2.0開始不再需要 是否開啓分桶功能 set hive.exec.dynamic.partition.mode = nonstrict; --動態分區模式 非嚴格 set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; -- set hive.compactor.initiator.on = true; --是否在Metastore實例上運行啓動線程和清理線程 set hive.compactor.worker.threads = 1; --在此metastore實例上運行多少個壓縮程序工作線程。 --2、創建Hive事務表 create table trans_student( id int, name String, age int )clustered by (id) into 2 buckets stored as orc TBLPROPERTIES('transactional'='true'); --3、針對事務表進行insert update delete操作 insert into trans_student (id, name, age) values (1,"allen",18); update trans_student set age = 20 where id = 1; delete from trans_student where id =1; select * from trans_student;
3.5 Hive View視圖
View的概念
Hive中的視圖(view)是一種虛擬表,只保存定義,不實際存儲數據。通常從真實的物理表查詢中創建生成視圖,也可以從已經存在的視圖上創建新視圖。
創建視圖時,將凍結視圖的架構,如果刪除或更改基礎表,則視圖將失敗,並且視圖不能存儲數據,操作數據,只能查詢。
概況起來就是:視圖是用來簡化操作的,它其實是一張虛表,在視圖中不緩衝記錄,也沒有提高查詢性能。
View相關語法
--hive中有一張真實的基礎表t_usa_covid19 select * from itcast.t_usa_covid19; --1、創建視圖 create view v_usa_covid19 as select count_date, county,state,deaths from t_usa_covid19 limit 5; --能否從已有的視圖中創建視圖呢 可以的 create view v_usa_covid19_from_view as select * from v_usa_covid19 limit 2; --2、顯示當前已有的視圖 show tables; show views;--hive v2.2.0之後支持 --3、視圖的查詢使用 select * from v_usa_covid19; --能否插入數據到視圖中呢? --不行 報錯 SemanticException:A view cannot be used as target table for LOAD or INSERT insert into v_usa_covid19 select count_date,county,state,deaths from t_usa_covid19; --4、查看視圖定義 show create table v_usa_covid19; --5、刪除視圖 drop view v_usa_covid19_from_view; --6、更改視圖屬性 alter view v_usa_covid19 set TBLPROPERTIES ('comment' = 'This is a view'); --7、更改視圖定義 alter view v_usa_covid19 as select county,deaths from t_usa_covid19 limit 2;
View的好處
1、將真實表中特定的列數據提供給用戶,保護數據隱式
--通過視圖來限制數據訪問可以用來保護信息不被隨意查詢: create table userinfo(firstname string, lastname string, ssn string, password string); create view safer_user_info as select firstname, lastname from userinfo; --可以通過where子句限制數據訪問,比如,提供一個員工表視圖,只暴露來自特定部門的員工信息: create table employee(firstname string, lastname string, ssn string, password string, department string); create view techops_employee as select firstname, lastname, ssn from userinfo where department = 'java';
2、降低查詢的複雜度,優化查詢語句
--使用視圖優化嵌套查詢 from ( select * from people join cart on(cart.pepople_id = people.id) where firstname = 'join' )a select a.lastname where a.id = 3; --把嵌套子查詢變成一個視圖 create view shorter_join as select * from people join cart on (cart.pepople_id = people.id) where firstname = 'join'; --基於視圖查詢 select lastname from shorter_join where id = 3;
3.6 物化視圖materialized views
物化視圖概念
在傳統的數據庫領域基本已經都實現了物化視圖, 屬於數據庫的高級功能。物化視圖(Materialized View)是一個包括查詢結果的數據庫對像,可以用於預先計算並保存表連接或聚集等耗時較多的操作的結果。這樣,在執行查詢時,就可以避免進行這些耗時的操作,而從快速的得到結果。使用物化視圖的目的就是通過預計算,提高查詢性能,當然需要佔用一定的存儲空間。
但是在SQL On Hadoop領域裏支持這個特性的還不多,比較令人期待。Hive3.0開始嘗試引入物化視圖,並提供對於物化視圖的查詢自動重寫(基於Apache Calcite實現)。值得注意的是,3.0中提供了物化視圖存儲選擇機制,可以本地存儲在hive,同時可以通過用戶自定義storage handlers存儲在其他系統(如Druid)。
Hive引入物化視圖的目的就是爲了優化數據查詢訪問的效率,相當於從數據預處理的角度優化數據訪問。Hive從3.0丟棄了index索引的語法支持,推薦使用物化視圖和列式存儲文件格式來加快查詢的速度。
物化視圖、視圖區別
- 視圖是虛擬的,邏輯存在的,只有定義沒有存儲數據。
- 物化視圖是真實的,物理存在的,裏面存儲着預計算的數據。
不同於視圖,物化視圖能夠緩存數據,在創建物化視圖的時候就把數據緩存起來了,hive把物化視圖當成一張“表”,將數據緩存。而視圖只是創建一個虛表,只有表結構,沒有數據,實際查詢的時候再去改寫SQL去訪問實際的數據表。
- 視圖的目的是簡化降低查詢的複雜度,而物化視圖的目的是提高查詢性能。
物化視圖語法
--物化視圖的創建語法 CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db_name.]materialized_view_name [DISABLE REWRITE] [COMMENT materialized_view_comment] [PARTITIONED ON (col_name, ...)] [CLUSTERED ON (col_name, ...) | DISTRIBUTED ON (col_name, ...) SORTED ON (col_name, ...)] [ [ROW FORMAT row_format] [STORED AS file_format] | STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)] ] [LOCATION hdfs_path] [TBLPROPERTIES (property_name=property_value, ...)] AS SELECT ...;
語法說明:
(1)物化視圖創建後,select查詢執行數據自動落地,"自動"也即在query的執行期間,任何用戶對該物化視圖是不可見的
(2)默認該物化視圖可被用於查詢優化器optimizer查詢重寫(在物化視圖創建期間可以通過DISABLE REWRITE參數設置禁止使用)
(3)SerDe和storage format非強制參數,可以用戶配置,默認可用hive.materializedview.serde、 hive.materializedview.fileformat
(4)物化視圖可以使用custom storage handlers存儲在外部系統(如druid)例如:
CREATE MATERIALIZED VIEW druid_wiki_mv STORED AS 'org.apache.hadoop.hive.druid.DruidStorageHandler' AS SELECT __time, page, user, c_added, c_removed FROM src;
目前支持物化視圖的drop和show操作,後續會增加其他操作
-- Drops a materialized view DROP MATERIALIZED VIEW [db_name.]materialized_view_name; -- Shows materialized views (with optional filters) SHOW MATERIALIZED VIEWS [IN database_name]; -- Shows information about a specific materialized view DESCRIBE [EXTENDED | FORMATTED] [db_name.]materialized_view_name;
當數據源變更(新數據插入inserted、數據修改modified),物化視圖也需要更新以保持數據一致性,目前需要用戶主動觸發rebuild
ALTER MATERIALIZED VIEW [db_name.]materialized_view_name REBUILD;
基於物化視圖的查詢重寫
物化視圖創建後即可用於相關查詢的加速,用戶提交查詢query,若該query經過重寫後可命中已建視圖,則被重寫命中相關已建視圖實現查詢加速。
是否重寫查詢使用物化視圖可以通過全局參數控制,默認爲true:
SET hive.materializedview.rewriting=true;
用戶可選擇性的失能物化視圖的重寫:
ALTER MATERIALIZED VIEW [db_name.]materialized_view_name ENABLE|DISABLE REWRITE;
案例:物化視圖查詢重寫
--1、新建一張事務表 student_trans set hive.support.concurrency = true; --Hive是否支持併發 set hive.enforce.bucketing = true; --從Hive2.0開始不再需要 是否開啓分桶功能 set hive.exec.dynamic.partition.mode = nonstrict; --動態分區模式 非嚴格 set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; -- set hive.compactor.initiator.on = true; --是否在Metastore實例上運行啓動線程和清理線程 set hive.compactor.worker.threads = 1; --在此metastore實例上運行多少個壓縮程序工作線程。 CREATE TABLE student_trans ( sno int, sname string, sdept string) clustered by (sno) into 2 buckets stored as orc TBLPROPERTIES('transactional'='true'); --2、導入數據到student_trans中 insert overwrite table student_trans select sno,sname,sdept from student; select * from student_trans; --3、對student_trans建立聚合物化視圖 CREATE MATERIALIZED VIEW student_trans_agg AS SELECT sdept, count(*) as sdept_cnt from student_trans group by sdept; --注意 這裏當執行CREATE MATERIALIZED VIEW,會啓動一個MR對物化視圖進行構建 --可以發現當下的數據庫中有了一個物化視圖 show tables; show materialized views; --4、對原始表student_trans查詢 --由於會命中物化視圖,重寫query查詢物化視圖,查詢速度會加快(沒有啓動MR,只是普通的table scan) SELECT sdept, count(*) as sdept_cnt from student_trans group by sdept; --5、查詢執行計劃可以發現 查詢被自動重寫爲TableScan alias: itcast.student_trans_agg --轉換成了對物化視圖的查詢 提高了查詢效率 explain SELECT sdept, count(*) as sdept_cnt from student_trans group by sdept;
第四章 Hive DDL其他語法
4.1 Database|schema(數據庫) DDL操作
Create database
Hive中DATABASE的概念和RDBMS中類似,我們稱之爲數據庫。在Hive中, DATABASE和SCHEMA是可互換的,使用DATABASE或SCHEMA都可以。
CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_name=property_value, ...)];
- COMMENT:數據庫的註釋說明語句
- LOCATION:指定數據庫在HDFS存儲位置,默認/user/hive/warehouse
- WITH DBPROPERTIES:用於指定一些數據庫的屬性配置。
下面創建一個數據庫:itheima
create database if not exists itheima comment "this is my first db" with dbproperties ('createdBy'='AllenWoon');
注意:使用location指定路徑的時候,最好是一個新創建的空文件夾。
Describe database
Hive中的DESCRIBE DATABASE語句用於顯示Hive中數據庫的名稱,其註釋(如果已設置)及其在文件系統上的位置等信息。
DESCRIBE DATABASE/SCHEMA [EXTENDED] db_name;
EXTENDED:用於顯示更多信息。
Use database
Hive中的USE DATABASE語句用於選擇特定的數據庫,切換當前會話使用哪一個數據庫進行操作。
USE database_name;
Drop database
Hive中的DROP DATABASE語句用於刪除(刪除)數據庫。
默認行爲是RESTRICT,這意味着僅在數據庫爲空時才刪除它。要刪除帶有表的數據庫,我們可以使用CASCADE。
DROP (DATABASE|SCHEMA) [IF EXISTS] database_name [RESTRICT|CASCADE];
Alter database
Hive中的ALTER DATABASE語句用於更改與Hive中的數據庫關聯的元數據。
--更改數據庫屬性 ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...); --更改數據庫所有者 ALTER (DATABASE|SCHEMA) database_name SET OWNER [USER|ROLE] user_or_role; --更改數據庫位置 ALTER (DATABASE|SCHEMA) database_name SET LOCATION hdfs_path;
5.2 Table(表)DDL操作
Describe table
Hive中的DESCRIBE table語句用於顯示Hive中表的元數據信息。
describe formatted [db_name.]table_name; describe extended [db_name.]table_name;
如果指定了EXTENDED關鍵字,則它將以Thrift序列化形式顯示錶的所有元數據。如果指定了FORMATTED關鍵字,則它將以表格格式顯示元數據。
Drop table
DROP TABLE刪除該表的元數據和數據。如果已配置垃圾桶(且未指定PURGE),則該表對應的數據實際上將移動到.Trash/Current目錄,而元數據完全丟失。刪除EXTERNAL表時,該表中的數據不會從文件系統中刪除,只刪除元數據。
如果指定了PURGE,則表數據不會進入.Trash/Current目錄,跳過垃圾桶直接被刪除。因此如果DROP失敗,則無法挽回該表數據。
DROP TABLE [IF EXISTS] table_name [PURGE]; -- (Note: PURGE available in Hive 0.14.0 and later)
Truncate table
從表中刪除所有行。可以簡單理解爲清空表的所有數據但是保留表的元數據結構。如果HDFS啓用了垃圾桶,數據將被丟進垃圾桶,否則將被刪除。
TRUNCATE [TABLE] table_name;
Alter table
--1、更改表名 ALTER TABLE table_name RENAME TO new_table_name; --2、更改表屬性 ALTER TABLE table_name SET TBLPROPERTIES (property_name = property_value, ... ); --更改表註釋 ALTER TABLE student SET TBLPROPERTIES ('comment' = "new comment for student table"); --3、更改SerDe屬性 ALTER TABLE table_name SET SERDE serde_class_name [WITH SERDEPROPERTIES (property_name = property_value, ... )]; ALTER TABLE table_name [PARTITION partition_spec] SET SERDEPROPERTIES serde_properties; ALTER TABLE table_name SET SERDEPROPERTIES ('field.delim' = ','); --移除SerDe屬性 ALTER TABLE table_name [PARTITION partition_spec] UNSET SERDEPROPERTIES (property_name, ... ); --4、更改表的文件存儲格式 該操作僅更改表元數據。現有數據的任何轉換都必須在Hive之外進行。 ALTER TABLE table_name SET FILEFORMAT file_format; --5、更改表的存儲位置路徑 ALTER TABLE table_name SET LOCATION "new location"; --6、更改列名稱/類型/位置/註釋 CREATE TABLE test_change (a int, b int, c int); // First change column a's name to a1. ALTER TABLE test_change CHANGE a a1 INT; // Next change column a1's name to a2, its data type to string, and put it after column b. ALTER TABLE test_change CHANGE a1 a2 STRING AFTER b; // The new table's structure is: b int, a2 string, c int. // Then change column c's name to c1, and put it as the first column. ALTER TABLE test_change CHANGE c c1 INT FIRST; // The new table's structure is: c1 int, b int, a2 string. // Add a comment to column a1 ALTER TABLE test_change CHANGE a1 a1 INT COMMENT 'this is column a1'; --7、添加/替換列 --使用ADD COLUMNS,您可以將新列添加到現有列的末尾但在分區列之前。 --REPLACE COLUMNS 將刪除所有現有列,並添加新的列集。 ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type,...);
4.3 Partition(分區)DDL操作
Add partition
分區值僅在爲字符串時才應加引號。位置必須是數據文件所在的目錄。
ADD PARTITION會更改表元數據,但不會加載數據。如果分區位置中不存在數據,查詢將不會返回任何結果。
--1、增加分區 ALTER TABLE table_name ADD PARTITION (dt='20170101') location '/user/hadoop/warehouse/table_name/dt=20170101'; --一次添加一個分區 ALTER TABLE table_name ADD PARTITION (dt='2008-08-08', country='us') location '/path/to/us/part080808' PARTITION (dt='2008-08-09', country='us') location '/path/to/us/part080809'; --一次添加多個分區
rename partition
--2、重命名分區 ALTER TABLE table_name PARTITION partition_spec RENAME TO PARTITION partition_spec; ALTER TABLE table_name PARTITION (dt='2008-08-09') RENAME TO PARTITION (dt='20080809');
delete partition
可以使用ALTER TABLE DROP PARTITION刪除表的分區。這將刪除該分區的數據和元數據。
--3、刪除分區 ALTER TABLE table_name DROP [IF EXISTS] PARTITION (dt='2008-08-08', country='us'); ALTER TABLE table_name DROP [IF EXISTS] PARTITION (dt='2008-08-08', country='us') PURGE; --直接刪除數據 不進垃圾桶
msck partition
Hive將每個表的分區列表信息存儲在其metastore中。但是,如果將新分區直接添加到HDFS(例如通過使用hadoop fs -put命令)或從HDFS中直接刪除分區文件夾,則除非用戶ALTER TABLE table_name ADD/DROP PARTITION在每個新添加的分區上運行命令,否則metastore(也就是Hive)將不會意識到分區信息的這些更改。
但是,用戶可以使用修復表選項運行metastore check命令。
--4、修復分區 MSCK [REPAIR] TABLE table_name [ADD/DROP/SYNC PARTITIONS];
MSC命令的默認選項是“添加分區”。使用此選項,它將把HDFS上存在但元存儲中不存在的所有分區添加到元存儲中。DROP PARTITIONS選項將從已經從HDFS中刪除的metastore中刪除分區信息。SYNC PARTITIONS選項等效於調用ADD和DROP PARTITIONS。
如果存在大量未跟蹤的分區,則可以批量運行MSCK REPAIR TABLE,以避免OOME(內存不足錯誤)。
alter partition
--5、修改分區 --更改分區文件存儲格式 ALTER TABLE table_name PARTITION (dt='2008-08-09') SET FILEFORMAT file_format; --更改分區位置 ALTER TABLE table_name PARTITION (dt='2008-08-09') SET LOCATION "new location";
第五章、Hive Show顯示語法
Show相關的語句提供了一種查詢Hive metastore的方法。可以幫助用戶查詢相關信息。
--1、顯示所有數據庫 SCHEMAS和DATABASES的用法 功能一樣 show databases; show schemas; --2、顯示當前數據庫所有表/視圖/物化視圖/分區/索引 show tables; SHOW TABLES [IN database_name]; --指定某個數據庫 --3、顯示當前數據庫下所有視圖 Show Views; SHOW VIEWS 'test_*'; -- show all views that start with "test_" SHOW VIEWS FROM test1; -- show views from database test1 SHOW VIEWS [IN/FROM database_name]; --4、顯示當前數據庫下所有物化視圖 SHOW MATERIALIZED VIEWS [IN/FROM database_name]; --5、顯示錶分區信息,分區按字母順序列出,不是分區表執行該語句會報錯 show partitions table_name; --6、顯示錶/分區的擴展信息 SHOW TABLE EXTENDED [IN|FROM database_name] LIKE table_name; show table extended like student; --7、顯示錶的屬性信息 SHOW TBLPROPERTIES table_name; show tblproperties student; --8、顯示錶、視圖的創建語句 SHOW CREATE TABLE ([db_name.]table_name|view_name); show create table student; --9、顯示錶中的所有列,包括分區列。 SHOW COLUMNS (FROM|IN) table_name [(FROM|IN) db_name]; show columns in student; --10、顯示當前支持的所有自定義和內置的函數 show functions; --11、Describe desc --查看錶信息 desc extended table_name; --查看錶信息(格式化美觀) desc formatted table_name; --查看數據庫相關信息 describe database database_name;