HIVE編程指南之HiveQL的學習筆記1

// HiveQL
a) 數據定義語言
1 數據庫
表的一個目錄或命名空間,若是用戶沒有指定數據庫的話,那麼將會使用默認的數據庫default
-----建立數據庫
CREATE DATABASE guoyongrong;// 給每一個數據庫建立了一個目錄,數據庫的文件目錄名是以.db結尾的
CREATE DATABASE IF NOT EXISTS guoyongrong; // 避免在數據庫存在的建立錯誤
CREATE DATABASE guoyongrong LOCATION '/my/preferred/directory'; // 修改目錄的位置
CREATE DATABASE guoyongrong COMMENT 'some comments';// 增長描述信息
CREATE DATABASE guoyongrong WITH DBPROPERTIES('creator'='gyr','date'='2015-07-21'); // 增長一些和其相關的鍵值對屬性信息java

-----查看Hive中包含的數據庫
SHOW DATABASES;
SHOW DATABASES LIKE 'h.*';//經過正則表達式篩選查找數據庫node

-----描述數據庫信息
DESCRIBE DATABASE guoyongrong;
DESCRIBE DATABASE EXTENDED guoyongrong;正則表達式

-----用於將某個數據庫設置爲用戶當前的工做數據庫
USE guoyongrong;
-----設置該屬性值來在提示符裏面顯示當前所在的數據庫
set hive.cli.print.current.db=true;
set hive.cli.print.current.db=false;數據庫

-----刪除數據庫
DROP DATABASE IF EXISTS guoyongrong; // 避免因數據庫不存在而拋出的警告信息
DROP DATABASE IF EXISTS guoyongrong CASCADE;// Hive是不容許用戶刪除一個包含有表的數據庫的。刪除該數據庫下的全部表後再刪除該數據庫
DROP DATABASE IF EXISTS guoyongrong RESTRICT; // 和默認狀況同樣,想刪除數據庫,那麼必需要刪除該數據庫中的全部表apache

-----修改數據庫
數據庫的其餘元數據信息都是不可更改的
ALTER DATABASE guoyongrong set DBPROPERTIES('edited-by'='gyr');// 修改DBPROPERTIES,沒有辦法刪除或者重置數據庫屬性數組

2 表
-----表建立
CREATE TABLE IF NOT EXISTS guoyongrong.employees( <------ 若是用戶當前所處的數據庫並不是是目標數據庫,能夠在表名上加數據庫名指定
name STRING COMMENT 'name',
salary FLOAT COMMENT 'salary',
subordinates ARRAY<STRING> COMMENT 'names of subordinates', <------ 爲每一個字段添加一個註釋
deductions MAP<STRING,FLOAT> COMMENT 'keys are deductions names,values are percentages',
address STRUCT<street:STRING,city:STRING,state:STRING,zip:INT> COMMENT 'home address'
)
COMMENT 'table descriptions' <------ 爲表自己添加一個註釋
TBLPROPERTIES('creator'='gyr','create_at'='2015-07-21 10:00:00',...) <------ 自定義一個或多個表屬性(按鍵值對的格式爲表增長額外的說明),Hive會自動增長2個表屬性:last_modified_by和last_modified_time
LOCATION '/user/hive/warehouse/guoyongrong.db/employees' <------ 爲表中的數據指定一個存儲路徑 數據倉庫路勁地址/數據庫目錄/表目錄 格式安全

-----拷貝一張已存在的表的表模式(無需拷貝數據)
CREATE TABLE IF NOT EXISTS guoyongrong.employees2
LIKE guoyongrong.employees
LOCATION '/path/to/data'; <------ LOCATION語句是可選的session

-----列舉出當前數據庫下全部的表
SHOW TABLES;
-----列舉出某個指定數據庫下全部的表
SHOW TABLES IN guoyongrong;
-----使用正則表達式過濾出所需的表
SHOW TABLES 'empl.*';
-----列舉出某表的TBLPROPERTIES屬性信息
SHOW TBLPROPERTIES guoyongrong.employees;架構

-----查看錶的詳細表結構信息
DESCRIBE EXTENDED guoyongrong.employees;
-----提供更加可讀和冗長的輸出信息
DESCRIBE FORMATTED guoyongrong.employees;
-----查看某一個列的信息
DESCRIBE guoyongrong.employees.salary;app

-----管理表,也稱爲內部表
Hive會控制 數據 的生命週期,默認狀況下,將數據存儲在配置項hive.metastore.warehouse.dir所定義的目錄的子目錄下
表會刪除,數據也會刪除
管理表不方便和其餘工做(pig等)共享數據

-----外部表
表會刪除,數據不會刪除
管理表和外部表小的區別是HiveQL語法結構並不適用於外部表.
-----管理表和外部表的選擇
若是數據會被多個工具共享,那麼就建立外部表,明確對數據的全部權

-----建立外部表
CREATE EXTERNAL TABLE IF NOT EXISTS stocks( <----- EXTERNAL告訴hive這個表示外部的
exchange STRING,
symbol STRING,
ymd STRING,
price_open FLOAT,
price_high FLOAT,
price_low FLOAT,
price_close FLOAT,
volume INT,
price_adj_close FLOAT
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/data/stocks' <----- 用於告訴Hive數據位於分佈式文件系統的/data/stocks目錄

-----能夠查看錶是不是管理表或外部表
DESCRIBE EXTENDED stocks;
...tableType:MANAGED_TABLE <----------管理表
...tableType:EXTERNAL_TABLE <----------外部表

----- 對一張存在的表進行表結構複製(不會複製數據)
CREATE EXTERNAL TABLE IF NOT EXISTS guoyongrong.employees3
LIKE guoyongrong.employees
LOCATION '/path/to/data'; <------ LOCATION語句是可選的

-----分區表(將數據以一種符合邏輯的方式進行組織,好比分層存儲)
分區管理表
CREATE TABLE employees(
name STRING,
salary FLOAT,
subordinates ARRAY<STRING>,
deductions MAP<STRING,FLOAT>,
address STRUCT<street:STRING,city:STRING,state:STRING,zip:INT>
)
PARTITIONED BY (country STRING, state STRING) <------ 改變了Hive對數據存儲的組織方式.分區字段爲country和state一旦建立好了,就和普通的字段一致
分區結構的子目錄
..../guoyongrong.db/employees/country=CA/state=AB
..../guoyongrong.db/employees/country=CA/state=BC
..../guoyongrong.db/employees/country=US/state=AL
..../guoyongrong.db/employees/country=US/state=AK

-----如下的查詢僅僅須要掃描一個目錄下的內容就能夠了.提升了性能
SELECT * FROM employees
WHERE country='US' AND state='IL'; <-----------在where語句中增長了分區值進行過濾,稱爲分區過濾器

-----若是表中的數據以及分區個數都很是大的話,執行這樣一個包含有全部分區的查詢可能會觸發一個巨大的MapReduce任務,安全措施是將Hive設置爲strict(嚴格)模式
hive> set hive.mapred.mode=strict;<---------對分區表進行查詢而WHERE字句沒有加分區過濾器的話,將會禁止提交該任務
SELECT e.name,e.salary FROM employees e LIMIT 100;<------FAILED
hive> set hive.mapred.mode=nonstrict;

-----查看錶中存在的全部分區
SHOW PARTITIONS employees;
-----查看錶中存在的特定分區
SHOW PARTITIONS employees PARTITION(country='US');
SHOW PARTITIONS employees PARTITION(country='US',state='AK');
-----也會顯示出分區鍵
DESCRIBE EXTENDED employees;

-----在管理表中用戶能夠經過載入數據的方式建立分區
LOAD DATA LOCAL INPATH '/home/hadoop/hive/guoyongrong/employees' <--------- 本地目錄
INTO TABLE employees
PARTITION (country='US',state='CA');<--------- 建立一個US和CA分區,用戶須要爲每一個分區字段指定一個值

外部分區表(管理大型生產數據集最多見的狀況)
給用戶提供了一個能夠和其餘工具共享數據的方式,同時也能夠優化查詢性能
用戶能夠自定義目錄結構,所以用戶對於目錄結構的使用具備更多的靈活性

-----建立外部分區表
CREATE EXTERNAL TABLE IF NOT EXISTS log_messages (
hms INT,
serverity STRING,
server STRING,
process_id INT,
message STRING
)
PARTITIONED BY (year INT,month INT,day INT) <------------按天劃分
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

-----對於外部分區表,經過ALTER TABLE語句能夠單獨進行增長分區.這個語句須要爲每個分區鍵指定一個值
ALTER TABLE log_message ADD PARTITION(year=2012,month=1,day=2) <------------ 增長一個2012年1月2日的分區
LOCATION 'hdfs://Master.hadoop:9000/data/hive/warehouse/guoyongrong.db/log_message/2012/01/02';<------------指定了數據路徑

-----咱們可使用Amazon S3的存儲設備存儲舊的數據,同時保存較新的數據到HDFS中
例如:天天可使用以下的處理過程將一個月前的舊數據轉移到S3中
1 將分區下的數據copy到Amazon S3
hadoop distcp /data/log_message/2011/12/02 s3n://ourbucket/logs/2011/12/02
2 修改表,將分區路徑指向s3路徑
ALTER TABLE log_message PARTITION(year=2011,month=12,day=2)
LOCATION 's3n://ourbucket/logs/2011/12/02';
3 刪除hdfs中的這個分區數據
hadoop fs -rmr /data/log_message/2011/12/02

-----能夠查看一個外部表的分區
SHOW PARTITIONS log_messages;
-----將分區鍵做爲表的模式一部分,和partitionKeys列表的內容同時進行顯示
DESCRIBE EXTENDED log_messages;
-----查看分區數據所在的路徑
DESCRIBE EXTENDED log_messages PARTITION(year=2011,month=12,day=2);

-----自定義表的存儲格式
CREATE TABLE employees(
name STRING,
salary FLOAT,
subordinates ARRAY<STRING>,
deductions MAP<STRING,FLOAT>,
address STRUCT<street:STRING,city:STRING,state:STRING,zip:INT>
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001' <------- 字段分隔符
COLLECTION ITEMS TERMINATED BY '\002' <------- 數組元素的分隔符
MAP KEYS TERMINATED BY '\003' <------- MAP 鍵的分隔符
LINES TERMINATED BY '\n' <------- 記錄行分隔符
STORED AS TEXTFILE; <-------TEXTFILE意味着全部字段都使用字母,數字,字符編碼,也意味着每一行都被認爲是一個單獨的記錄
能夠替換爲SEQUENCEFILE和RCFILE,這個兩種文件格式都是使用二進制編碼和壓縮來優化磁盤空間使用以及IO帶寬性能的

CREATE TABLE kst
PARTITIONED BY (ds STRING)
ROW FORMAT SERDE 'com.linkedin.haivvreo.AvroSerDe' <------ 指定使用的SerDe
WITH SERDEPROPERTIES ('schema.url'='http://schema_provider/kst.avsc') <------ 容許用戶傳遞配置信息給SerDe
STORED AS
INPUTFORMAT 'com.linkedin.haivvreo.AvroContainerInputFormat' <------ 指定用於輸入格式的java類
OUTPUTFORMAT 'com.linkedin.haivvreo.AvroContainerOutputFormat' <------ 指定用於輸出格式的java類

用DESCRIBE EXTENDED kst命令會在DETAILED TABLE INFORMATION部分列舉出輸入和輸出格式以及SerDe的屬性信息

CREATE EXTERNAL TABLE IF NOT EXISTS stocks(
exchange STRING,
symbol STRING,
ymd STRING,
price_open FLOAT,
price_high FLOAT,
price_low FLOAT,
price_close FLOAT,
volume INT,
price_adj_close FLOAT
)
CLUSTERED BY (exchange,symbol) <------- 用來優化某些特定的查詢
SORTED BY (ymd ASC) <------- 可選
INTO 96 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/data/stocks' <--- 分佈式文件系統的/datastocks目錄

-----刪除表
DROP TABLE IF EXISTS employees;
對於管理表,表的元數據信息和表內的數據都會被刪除
對於外部表,表的元數據信息會被刪除,可是表中的數據不會被刪除

-----修改表(修改表的元數據,不會修改數據自己)
----------重命名
ALTER TABLE log_messages RENAME TO logmsgs;

----------增長表分區
ALTER TABLE log_messages ADD IF NOT EXISTS
PARTITION (year=2011,month=1,day=1) LOCATION '/logs/2011/01/01' <------- 增長(year=2011,month=1,day=1)的分區 數據存放的路徑 '/logs/2011/01/01'
PARTITION (year=2011,month=1,day=2) LOCATION '/logs/2011/01/02'
PARTITION (year=2011,month=1,day=3) LOCATION '/logs/2011/01/03';

----------修改分區路徑
ALTER TABLE log_messages PARTITION (year=2011,month=1,day=1) <------- 修改(year=2011,month=1,day=1)分區的數據存放的路徑爲 's3n://ourbucket/logs/2011/01/02'
SET LOCATION 's3n://ourbucket/logs/2011/01/02';

----------刪除分區
ALTER TABLE log_messages DROP IF EXISTS PARTITION (year=2011,month=1,day=1);
對於管理表,即便是使用ALTER TABLE ... ADD PARTITION增長的分區,分區內的數據也是會同時和元數據信息一塊兒被刪除的。
對於外部表,分區內數據不會被刪除

----------修改列信息
ALTER TABLE log_messages
CHANGE COLUMN hms hours_minutes_seconds INT <--------- 即便字段名護照地段類型沒有改變,用戶也要徹底自定舊的字段名,並給出新的字段名及新的字段類型
COMMENT 'The hours,minutes, and seconds part of the timestamp'
AFTER serverity;<--------- 若是用戶想將這個字段移動到第一個位置,那麼只需用FIRST 關鍵字 代替AFTER other_column字句便可

----------增長列
ALTER TABLE log_messages ADD COLUMNS (
app_name STRING COMMENT 'xxx',
session_id LONG COMMENT 'xxxx'
)

----------刪除或替換列
ALTER TABLE log_messages REPLACE COLUMNS (
hours_mins_secs INT COMMENT 'xxx',
serverity STRING COMMENT 'xxx',
message STRING COMMENT 'xxx'
)

----------修改表屬性,能夠增長和修改表屬性,但不能刪除
ALTER TABLE log_messages SET TBLPROPERTIES(
'notes'='xxxx'
)

----------修改存儲屬性
ALTER TABLE log_messages
PARTITION(year=2012,month=1,day=1) <-----將(year=2012,month=1,day=1)分區的存儲格式修改爲SEQUENCEFILE
SET FILEFORMAT SEQUENCEFILE;

ALTER TABLE table_using_JSON_storage
SET SERDE 'com.example.JSONSerDe' <------指定新的SerDe
WITH SERDEPROPERTIES( <----------該屬性會被傳遞給SerDe模塊
'prop1'='value1',
'prop2'='value2',
)

ALTER TABLE table_using_JSON_storage
SET SERDEPROPERTIES( <----------給已經存在的SerDe增長新的SERDEPROPERTIES屬性
'prop3'='value3',
'prop4'='value4',
)

ALTER TABLE stocks
CLUSTERED BY (exchange,symbol)
SORTED BY (symbol) <-------- 該語句可選
INTO 48 BUCKETS;

----------觸發鉤子 當表中存儲的文件在HIVE以外被修改了,就會觸發鉤子的執行
ALTER TABLE log_messages TOUCH
PARTITION(year=2012,month=1,day=1)

----------將某分區內的文件打成一個hadoop壓縮包(HAR)文件,僅下降文件系統的文件數以及減輕NameNode的壓力,不會減小任何的存儲空間
ALTER TABLE log_messages ARCHIVE
PARTITION(year=2012,month=1,day=1)

----------防止分區被刪除
ALTER TABLE log_messages
PARTITION(year=2012,month=1,day=1)
ENABLE NO_DROP; <----- DISABLE

----------防止分區被查詢
ALTER TABLE log_messages
PARTITION(year=2012,month=1,day=1)
ENABLE OFFLINE; <----- DISABLE

3 視圖 <----- 能夠容許保存一個查詢並像對待表同樣對這個查詢進行操做;不能做爲INSERT或LOAD語句的目標表
------使用視圖來下降查詢複雜度
FROM(
SELECT * FROM people INNER JOIN cart
ON (cart.people_id=people.id)
WHERE firstname='john'; <----- 嵌套查詢
) a
SELECT a.lastname
WHERE a.id=3;

------建立視圖
CREATE VIEW shorter_join AS
SELECT * FROM people INNER JOIN cart
ON (cart.people_id=people.id)
WHERE firstname='john';

SELECT lastname FROM shorter_join WHERE id=3;
------使用視圖來限制基於條件過濾的數據
CREATE TABLE userinfo(
firstname STRING,lastname STRING,ssn STRING,password STRING
);
CREATE VIEW safer_user_info AS <----- 經過視圖來限制數據訪問能夠用來保護信息不被隨意查詢
SELECT firstname,lastname FROM userinfo;

CREATE TABLE employee(
firstname STRING,lastname STRING,ssn STRING,password STRING,department STRING)
);
CREATE VIEW techops_employee AS <----- 經過WHERE字句顯示數據訪問只暴露來自特定部門的員工信息
SELECT firstname,lastname,ssn FROM employee
WHERE department='techops'

CREATE EXTERNAL TABLE dynamictable(cols MAP<STRING,STRING>)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\004'
COLLECTION ITEMS TERMINATED BY '\001'
MAP KEYS TERMINATED BY '\002'
STORED AS TEXTFILE;
CREATE VIEW orders(state,city,part) AS
SELECT cols["state"],cols["city"],cols["part"]
FROM dynamictable
WHERE cols["type"] = 'request';

CREATE VIEW IF NOT EXISTS shipments(time,part) <----- IF NOT EXISTS 字句是可選的
COMMET 'Time and parts for shipments' <----- COMMET 字句是可選的
TBLPROPERTIES('creator'='me') <----- 經過定義TBLPROPERTIES來定義視圖屬性信息
AS SELECT ....;

------CREATE TABLE ... LIKE ...複製視圖
CREATE TABLE shipments2
LIKE shipments;<----- shipments是視圖名

------刪除視圖
DROP VIEW IF EXISTS shipments;
------SHOW TABLES 查看到視圖,沒有SHOW VIEWS命令
------DESCRIBE EXTENDED 能夠顯示視圖的元數據信息,輸出信息中的"Detailed Table Information"部分會有一個tableType字段,字段值顯示的是"VIRTUAL_VIEW"

------修改視圖
ALTER VIEW shipments SET TBLPROPERTIES('created_at'='some_timestamp');<---------- 視圖是隻讀的,只容許改變元數據中TBLPROPERTIES屬性信息;

4 索引
------建立索引
CREATE INDEX employees_index
ON TABLE employees(country)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' <--------- AS ... 語句指定了索引處理器,也就是一個實現了索引接口的JAVA類
WITH DEFERRED REBUILD <--------- 若是用戶指定了 DEFERRED REBUILD,那麼新索引將呈現空白狀態
IDXPROPERTIES ('creator'='me','created_at'='some_time')
IN TABLE employees_index_table <---------要求索引處理器在一張新表中保留索引數據. IN TABLE語句可選
PARTITIONED BY(country,name) <--------- 若是省略掉PARTITIONED BY語句的話,那麼索引將會包含原始表的全部分區
COMMENT 'Employees indexed by country and name.'

CREATE INDEX employees_index
ON TABLE employees(country)
AS 'BITMAP' <--------- 內置的bitmap索引處理器.bitmap索引廣泛應用於排重後值較少的列
WITH DEFERRED REBUILD
IDXPROPERTIES ('creator'='me','created_at'='some_time')
IN TABLE employees_index_table
PARTITIONED BY(country,name) <--------- 若是省略掉PARTITIONED BY語句的話,那麼索引將會包含原始表的全部分區
COMMENT 'Employees indexed by country and name.'

------重建索引
ALTER INDEX employees_index
ON TABLE employees
PARTITON (country = 'US') <---- 若是省略掉PARTITION,那麼將會對全部分區進行重建索引
REBUILD;
------顯示索引
SHOW FORMATTED INDEX ON employees;<---- FROMATTED是可選的,可使輸出中包含有列名稱
SHOW FORMATTED INDEXES ON employees;<---- 能夠列舉出多個索引信息
------刪除索引
DROP INDEX IF EXISTS employees_index ON TABLE employees;<---- 不容許用戶直接使用DROP TABLE 語句以前刪除索引表
若是被索引的表被刪除了,那麼其對應的索引和索引表也會被刪除.一樣的,若是原始表的某個分區被刪除了,那麼這個分區對應的分區索引頁同時會被刪除

b) 數據操做語言
-----向管理表中裝載數據
LOAD DATA LOCAL INPATH '${env:HOME}/california-employees' <---------若是指定local那麼是本地路徑,不然是分佈式文件系統的路徑,這個路徑下不能夠包含任何文件夾,同時Hive會驗證文件格式是否和表結構定義一致
OVERWRITE INTO TABLE employees <--------- OVERWRITE使得目標文件夾中以前存在的數據將會被先刪除,若是沒有這個關鍵字,僅僅會把新增的文件增長到目標文件
PARTITION(country='US',state='CA'); <--------- 若是分區目錄不存在的話,會先建立分區目錄,而後將數據copy到該目錄,若是是非分區表,PARTITION字句能夠省略

-----經過查詢語句向表中插入數據
INSERT OVERWRITE TABLE employees <--------- 若是沒有OVERWRITE關鍵字或者使用INTO關鍵字的話,那麼Hive將會以追加的方式寫入數據而不會覆蓋掉以前已經存在的內容
PARTITION (country='US',state='OR')
SELECT * FROM staged_employees se
WHERE se.cnty='US' AND se.st='OR';

-----能夠只掃描一次表數據
FROM staged_employees se <--------- 從staged_employees表中讀取的每條記錄都會通過一條SELECT ... WHERE ... 句子進行判斷。若是知足某個的話沒,就被寫入到指定的表和分區中
INSERT OVERWRITE TABLE employees
PARTITION (country='US',state='OR')
SELECT * WHERE se.cnty='US' AND se.st='OR'
INSERT OVERWRITE TABLE employees
PARTITION (country='US',state='CA')
SELECT * WHERE se.cnty='US' AND se.st='CA'
INSERT OVERWRITE TABLE employees
PARTITION (country='US',state='IL')
SELECT * WHERE se.cnty='US' AND se.st='IL' ;

-----動態分區插入(Hive根據SELECT語句最後2列來肯定分區字段country和state的值)
INSERT OVERWRITE TABLE employees
PARTITION (country,state)
SELECT ..., se.cnty, se.st
FROM staged_employees se;

-----混合使用動態和靜態分區插入(country字段是靜態的US,而state是動態值)
INSERT OVERWRITE TABLE employees
PARTITION (country = 'US',state) <--------- 靜態分區鍵必須出如今動態分區鍵以前
SELECT ..., se.cnty, se.st
FROM staged_employees se
WHERE se.cnty ='US';

動態分區功能默認是沒有開啓,開啓後,默認是以 嚴格 模式執行的。 這種模式下要求至少有一列分區字段是靜態的。有助於因設計錯誤致使查詢產生大量的分區
動態分區屬性
hive.exec.dynamic.partition false 設置成true,表示開啓動態分區功能
hive.exec.dynamic.partition.mode strict 設置成nonstrict,表示容許全部分區都是動態的
hive.exec.max.dynamic.partitions.pernode 100 每一個mapper或reducer能夠建立的最大動態分區個數.若是某個mapper或reducer嘗試建立大於這個值的分區的話則會拋出一個致命錯誤信息
hive.exec.max.dynamic.partitions +1000 一個動態分區建立語句能夠建立的最大動態分區個數.若是超過這個值則會拋出一個致命錯誤信息
hive.exec.max.created.files 100000 全局能夠建立額最大文件個數.有一個hadoop計數器會跟蹤記錄建立了多少個文件,若是超過這個值則會拋出一個致命錯誤信息

hive>set hive.exec.dynamic.partition = true;
hive>set hive.exec.dynamic.partition.mode = nonstrict;
hive>set hive.exec.max.dynamic.partitions.pernode = 1000;
INSERT OVERWRITE TABLE employees
PARTITION (country,state)
SELECT ..., se.cnty, se.st
FROM staged_employees se;

-----單個查詢語句中建立表並加載數據(從一個寬表中選取部分須要的數據集,這個不能用於外部表)
CREATE TABLE ca_employees
AS
SELECT name,salary,address
FROM employees
WHERE state ='CA';

-----導出數據
hadoop fs -cp source_path target_path;<----- 數據文件是用戶須要的格式,那麼只須要copy文件或文件夾就能夠了

INSERT OVERWRITE LOCAL DIRECTORY '/tmp/ca_employees'
SELECT name,salary,address
FROM employees
WHERE state ='CA';
在hive CLI中查看導出的目錄
hive> ! ls /temp/ca_employees;
hive> ! cat /temp/ca_employees/000000_0;

-----經過以下的方式指定多個輸出文件夾
FROM staged_employees se <--------- 從staged_employees表中讀取的每條記錄都會通過一條SELECT ... WHERE ... 句子進行判斷。若是知足某個的話沒,就被寫入到指定的表和分區中
INSERT OVERWRITE DIRECTORY '/tmp/or_employees'
SELECT * WHERE se.cnty='US' AND se.st='OR'
INSERT OVERWRITE DIRECTORY '/tmp/ca_employees'
SELECT * WHERE se.cnty='US' AND se.st='CA'
INSERT OVERWRITE DIRECTORY '/tmp/il_employees'
SELECT * WHERE se.cnty='US' AND se.st='IL' ;

c) 查詢
-----SELECT... FROM 語句
SELECT name,salary FROM employees;<-----SELECT 指定要保存的列以及輸出函數須要調用的一個或多個列,FORM標示從哪一個表,視圖,嵌套查詢中選擇記錄
SELECT e.name,e.salary FROM employees e;<----- 指定了表別名,用於連接操做
SELECT name,subordinates,address,deductions FROM employees;<----- 選擇的列是集合數據類型時,Hive會使用JSON語法應用於輸出.
SELECT name,subordinates[0],address.city,deductions["State Taxes"] FROM employees;<----- 展現查詢數組類型,MAP類型,STRUCT類型字段裏面內容的用法
SELECT symbol,`price.*` FROM stocks;<----- 使用正則表達式來指定列
SELECT upper(name),salary,decuctions["Federal Taxes"],round(salary * (1- deductions["Federal Taxes"])) FROM employees;<----- 使用函數調用和算術表達式操做列值
SELECT upper(name),salary FROM employees limmit 2;<-----------limit用於限制返回的行數
SELECT upper(name) AS upper_name FROM employees;<-----------AS ... 定義了列別名
SELECT name,salary,
CASE <-----------CASE ... WHEN ... THEN 語句
WHEN salary < 50000.0 THEN 'low'
WHEN salary >= 50000.0 AND salary < 70000.0 THEN 'middle'
WHEN salary >= 70000.0 AND salary < 100000.0 THEN 'high'
ELSE 'very high'
END As bracket FROM employees;

FROM(
SELECT upper(name),salary,deductions["Federal Taxes"] as fed_taxes,round(salary *(1-deductions["Federal Taxes"])) as salary_minus_fed_taxes
FROM employees <-----------嵌套查詢
) e <------------ e 作爲嵌套查詢的別名
SELECT e.name,e.salary_minus_fed_taxes
WHERE e.salary_minus_fed_taxes > 70000;

-----WHERE 語句 <-----------過濾條件
SELECT name,salary,deductions["Federal Taxes"],
salary * (1-deductions["Federal Taxes"])
FROM employees
WHERE round(salary * (1-deductions["Federal Taxes"])) > 70000 <------- 不能在WHERE語句中使用列別名,但可使用嵌套的select語句

SELECT e.* FROM
(
SELECT name,salary,deductions["Federal Taxes"],
salary * (1-deductions["Federal Taxes"]) as salary_minus_fed_taxes
FROM employees
) e
WHERE round(e.salary_minus_fed_taxes) > 70000

-----函數
----------數學函數
----------聚合函數 <---------- 對多行進行一些計算,而後獲得一個結果值
hive>set hive.map.aggr=true; <--------能夠提升聚合的性能
SELECT count(*),avg(salary) FROM employees;
SELECT count( DISTINCT symbol),avg(salary) FROM stocks;<--------- 不少函數均可以接受 DISTINCT...表達式
----------表生成函數 <---------- 將單列擴展成多列或者多行
SELECT explode(subordinates) AS sub FROM employees;<-----------subordinates 字段內容爲空的話,那麼不產生新的記錄,不然,這個數組的每一個元素都將產生一行新記錄,同時,當使用表生成函數時,要求使用列別名
SELECT parse_url_tuple(url,'HOST','PATH','QUERY') as (host,path,query) FROM url_table;<-----------擴展多列的例子
----------其餘內置函數 <----------用於處理字符串,Map,數組,JSON和時間戳

-----什麼狀況下Hive能夠避免進行MapReduce
本地模式
WHERE語句中過濾條件只是分區字段這種狀況
屬性hive.exec.mode.local.auto的值設置爲true的話,Hive會嘗試使用本地模式執行其餘的操做

-----謂詞操做符 能夠用於JOIN ... ON和HAVING語句中
操做符 支持的數據類型 描述
A=B 基本數據類型 若是A等於B則返回true,反之返回false
A<=>B 基本數據類型 若是A和B都爲NULL則返回TRUE,其餘的和等號(=)操做符一致,若是任一爲NULL則結果爲NULL
A==B 沒有 錯誤的語法SQL使用=,而不是==
A IS [NOT] NULL 全部數據類型 若是A等於[不等於] NULL,則返回TRUE;反之返回FALSE
A [NOT] LIKE B STRING類型 B是一個SQL下的簡單正則表達式,若是A與其匹配的話,則返回TRUE反之返回FALSE,B的表達式說明以下:'x%'表示A必須以字母'x'開頭,'%x'表示A必須以字母'x'結尾,而'%x%'表示A包含字母'x'.下劃線'_'匹配單個字符.
A RLIKE B,A REGEXP B STRING類型 B是一個正則表達式,若是A與其相匹配,則返回TRUE,反之返回FALSE.匹配使用的是JDK中的正則表達式接口實現的.

-----關於浮點數比較
SELECT name,salary,deductions['Federal Taxes']
FROM employees WHERE deductions['Federal Taxes'] >0.2; <------這個查詢會將0.2的記錄也查詢出來.
形成該問題的緣由是 數字0.2是不可以使用FLOAT或DOUBLE進行準確表示的
數字0.2對於FLOAT類型時0.2000001,而對於DOUBLE類型時0.200000000001,由於一個8個字節的DOUBLE值具備更多的小數位,
當表的FLOAT值經過Hive轉換爲DOUBLE值時,其產生的DOUBLE值時0.200000100000,
這個值實際要比0.200000000001大.這個問題是全部使用IEEE標準進行浮點數編碼的系統中存在的一個廣泛的問題.
規避該問題的方法有3種
定義表字段的類型的爲DOUBLE而不是FLOAT,但會形成查詢時所需的內存消耗,同時若是表額存儲格式是二進制文件格式的話,也不能簡單的進行這樣的改變
顯示的指出0.2爲FLOAT類型的.Hive必須使用cast操做符進行類型轉換.修改查詢語句將0.2的DOUBLE類型轉爲FLOAT類型,cast(0.2 AS FLOAT)
和錢相關的都避免使用浮點數

-----LIKE和RLIKE
SELECT name,address.street FROM employees WHERE address.street LIKE '%Ave.';
SELECT name,address.city FROM employees WHERE address.city LIKE 'O%';
SELECT name,address.street FROM employees WHERE address.street LIKE '%Chi%';
SELECT name,address.street FROM employees WHERE address.street RLIKE '.*(Chicago|Ontario).*';<----java的正則表達式

-----GROUP BY 語句
SELECT year(ymd),avg(price_close) FROM stocks <------- group by 語句一般會和聚合函數一塊兒使用,按照一個或者多個列對結果進行分組,而後對每一個組執行聚合操做
WHERE exchange='NASDAQ' AND symbol='AAPL'
GROUP BY year(ymd);
-----HAVING 語句
SELECT year(ymd),avg(price_close) FROM stocks
WHERE exchange='NASDAQ' AND symbol='AAPL'
GROUP BY year(ymd)
HAVING avg(price_close) >50.0 <------- HAVING 語句容許用戶經過一個簡單的語法完成本來須要經過子查詢才能對GROUP BY語句產生的分組進行條件過濾的任務.
----------若是沒有HAVING字句,那麼須要使用一個嵌套的SELECT子查詢
SELECT s2.year,s2.avg FROM
(
SELECT year(ymd) AS year,avg(price_close) AS avg FROM stocks
WHERE exchange='NASDAQ' AND symbol='AAPL'
GROUP BY year(ymd)
) s2
WHERE s2.avg >50.0

-----JOIN 語句
----------INNER JOIN(內鏈接)
SELECT a.ymd,a.price_close,b.price_close
FROM stocks a INNER JOIN stocks b ON a.ymd = b.ymd <------ 只有進行鏈接的兩個表中都存在與鏈接標準相匹配的數據纔會被保留下來,ON字句指定了兩個表間數據進行鏈接的條件.Hive不支持非等值鏈接以及在ON字句中的謂詞間使用OR
WHERE a.symbol=''AAPL AND b.symbol='IBM'

CREATE EXTENRNAL TABLE IF NOT EXISTS dividends(
ymd STRING,
dividend FLOAT
)
PARTITIONED BY(exchange STRING,symbol STRING)<---------按分區鍵exchange和symbol進行分區
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

SELECT s.ymd,s.symbol,s.price_close,d.dividend
FROM stocks s INNER JOIN dividends d ON s.ymd = d.ymd AND s.symbol = d.symbol
WHERE s.symbol='AAPL';

SELECT a.ymd,a.price_close,b.price_close,c.price_close
FROM stocks a INNER JOIN stocks b ON a.ymd = b.ymd <-------- 多表管理,大多數狀況下,Hive會對每一個JOIN鏈接對象啓動一個MapReduce任務.Hive老是按照從左到右的順序進行鏈接操做
INNER JOIN stocks c ON a.ymd = c.ymd
WHERE a.symbol='AAPL' AND b.symbol='IBM' AND c.symbol='GE'

----------LEFT OUTER JOIN(左外鏈接)
SELECT s.ymd,s.symbol,s.price_close,d.dividend <------ 返回左邊表中全部符合WHERE語句的記錄,右邊表中匹配不上的字段值用NULL代替
FROM stocks s LEFT OUTER JOIN dividends
ON s.ymd=d.ymd AND s.symbol=d.symbol <------ 先作兩個表的鏈接操做,而後在作WHERE過濾,ON語句中的 分區過濾條件 在外連接中無效,在內鏈接中是有效的
WHERE s.symbol='AAPL';<------WHERE語句在鏈接操做執行完後纔會執行.

----------RIGHT OUTER JOIN(右外鏈接)
SELECT s.ymd,s.symbol,s.price_close,d.dividend <------ 返回右邊表中全部符合WHERE語句的記錄,左邊表中匹配不上的字段值用NULL代替
FROM dividends d RIGHT OUTER JOIN stocks s
ON d.ymd=s.ymd AND d.symbol=s.symbol
WHERE s.symbol='AAPL';

----------FULL OUTER JOIN(徹底外鏈接)
SELECT s.ymd,s.symbol,s.price_close,d.dividend <------ 返回全部表中全部符合WHERE語句的記錄,若是任一表的指定字段沒有符合條件的值的話,那麼就使用NULL值替代
FROM dividends d FULL OUTER JOIN stocks s
ON d.ymd=s.ymd AND d.symbol=s.symbol
WHERE s.symbol='AAPL';

----------LEFT SEMI-JOIN(左半開鏈接) <------ 一般比INNER JOIN要更高效,緣由以下:對於左表中一條指定的記錄,在右邊表中一旦找到匹配的記錄,Hive就會當即中止掃描,Hive不支持RIGHT SEMI-JOIN(右半開鏈接)
SELECT s.ymd,s.symbol,s.price_close <------ 返回全部表中全部符合WHERE語句的記錄,若是任一表的指定字段沒有符合條件的值的話,那麼就使用NULL值替代
FROM stocks s
WHERE s.ymd,s.symbol IN <------IN 在hive中不支持
(
SELECT d.ymd,d.symbol FROM dividends d;
)

SELECT s.ymd,s.symbol,s.price_close <------ 返回左邊表中全部符合WHERE語句的記錄,前提是其記錄對於右邊表知足ON語句中的斷定條件,注意SELECT和WHERE語句中不能引用到右邊表中的字段.
FROM stocks s LEFT SEMI JOIN dividends d
ON s.ymd=d.ymd AND s.symbol=d.symbol

----------笛卡爾積JOIN <------ 設置hive.mapred.mode值爲strict的話,Hive會阻止用戶執行笛卡兒積查詢
SELECT * FROM stocks JOIN dividends;<------ 表示左邊表的行數 * 右邊表的行數等於笛卡爾結果集的大小,笛卡爾積不是並行執行的,並且使用了MapReduce計算架構的話,任何方式都沒法進行優化
SELECT * FROM stocks JOIN idvidends
WHERE stock.symbol=dividends.symbol AND stock.symbol='AAPL';<------ 在其餘的數據庫中會被優化成內鏈接,可是在Hive中沒有此優化;WHERE語句中的謂詞條件前會先進行徹底笛卡兒積計算

----------map-side JOIN <------ 若是全部表中只有一張表是小表,那麼能夠在最大的表經過mapper的時候將小表徹底放到內存中,Hive能夠在map端執行鏈接過程(稱爲map-side JOIN),這是由於Hive能夠和內存中的小表進行逐一匹配,從而省略掉常規鏈接操做所需的reduce過程
SELECT /*+ MAPJOIN(d) */ s.ymd,s.symbol,s.price_close,d.dividend <------ 經過該標記,能夠啓動這個優化
FROM stocks s INNER JOIN dividends d ON s.ymd =d.ymd AND s.symbol=d.symbol
WHERE s.symbol='AAPL';

set hive.auto.convert.join = true;<------ 設置hive.auto.convert.JOIN值爲true,這樣Hive纔會在必要的時候啓動這個優化,默認該屬性的值爲false;
set hive.mapjoin.smalltable.filesize = 25000000;<------ 用戶也能夠配置可以使用這個優化的小表的大小(單位是字節)
若是用戶指望hive在必要的時候自動啓動這個優化的話,那麼能夠將這兩個屬性設置放在$HOME/.hiverc文件中,對於RIGHT和FULL OUTER JOIN不支持這個優化

SELECT s.ymd,s.symbol,s.price_close,d.dividend
FROM stocks s INNER JOIN dividends d ON s.ymd =d.ymd AND s.symbol=d.symbol
WHERE s.symbol='AAPL';

set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin=true;<------ 若是全部表的數據是分桶的,當表中的數據必須是按照ON語句中的鍵進行分桶的,並且其中的一張表的分桶的個數必須是另外一張表分桶個數的若干倍,當知足這些條件時,那麼Hive能夠在map階段按照分桶數據進行鏈接
set hive.optimize.bucketmapjoin.sortedmerge=true;<------ 若是所涉及的分桶表都具備相同的分桶數,並且數據是按照鏈接鍵進行排序的,那麼Hive能夠執行一個更快的分類-合併鏈接(sort-merge JOIN)

-----JOIN 優化
1)當對3個或更多表進行JOIN鏈接時,若是每一個ON字句都使用相同的鏈接鍵的話,那麼只會產生一個MapReduce Job
2)Hive同時假定查詢中最後一個表示最大的那個表,所以用戶須要保證鏈接查詢中的表的大小是從左到右是一次增長的.
3)Hive提供了一個 標記 機制來顯示的告知查詢優化器哪張表是大表
SELECT /*+STREAMTABLE(s) */ s.ymd,s.symbol,s.price_close,d.dividend
FROM stocks s JOIN dividends d ON s.ymd=d.ymd AND s.symbol=d.symbol
WHERE s.symbol='AAPL';
4) map_side JOIN

----------ORDER BY和SORT BY
ORDER BY會對查詢結果集執行一個全局排序。也就是說會有一個全部的數據都經過一個reducer進行處理的過程。對於大數據集,這個過程會消耗太過漫長的時間來執行
SORT BY 會在每一個reducer中對數據進行排序,也就是執行一個局部排序過程,保證每一個reducer的輸出數據都是有序的(但並不是全局有序)
SELECT s.ymd,s.symbol,s.price_close
FROM stocks s
ORDER BY s.ymd ASC,s.symbol DESC;<---------- 若是設置hive.mapred.mode的值是strict的話,那麼Hive要求必須加有LIMIT語句進行限制
SORT BY s.ymd ASC,s.symbol DESC;<---------- 若是使用的reducer的個數大於1的話。那麼兩個查詢輸出結果的排序就不同了

----------含有SORT BY的DISTRIBUTE BY <---------- DISTRIBUTE BY控制map的輸出在reducer中是如何劃分的。
SELECT s.ymd,s.symbol,s.price_close
FROM stocks s
DISTRIBUTE BY s.symbol <---------- 使用DISTRIBUTE BY來保證具備相同股票交易碼的記錄會分發到同一個reducer中進行處理,而後使用sort by對數據進行排序;DISTRIBUTE BY語句要寫在SORT BY語句以前
SORT BY s.symbol ASC,s.ymd ASC;

----------ClUSTER BY <----------在DISTRIBUTE BY語句中和SORT BY語句中涉及到列徹底相同的話,並且採用的是升序排序方式,那麼CLUSTER BY就等價於前面的2個語句
SELECT s.ymd,s.symbol,s.price_close
FROM stocks s
CLUSTER BY s.symbol;<----------DiSTRIBUTE BY ... SORT BY語句或其簡化版的CLUSTER BY語句會剝奪SORT BY的並行性,然而能夠實現輸出文件的數據是全局排序的

----------Cast()函數<----------對指定的值進行顯示的類型轉換
SELECT name,salary FROM employees
WHERE cast(salary AS FLOAT) < 100000.0; <----------類型轉換函數的語法是cast(value AS TYPE)
將浮點數轉換成整數的推薦方式是使用round()或者floor()函數,而不是使用類型轉換操做符cast
對於BINARY類型,目前只支持將BINARY類型轉換爲STRING類型,若是用戶知道其值是數值的話,那麼能夠經過嵌套cast()的方式對其進行類型轉換
SELECT (2.0 * cast(cast(b as STRING) as DOUBLE)) FROM SRC;

----------抽樣查詢 <----------對於一個很是大的數據集,用戶須要使用的是一個具備表明性的查詢結果而不是所有結果,Hive經過對錶進行分桶抽樣來知足這個需求
CREATE TABLE numbers(number int);
insert into numbers values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
SELECT * FROM numbers <----------number表只有number字段,其值是1到10
TABLESAMPLE(BUCKET 3 OUT OF 10 ON rand()) s;<---------- 使用rand()函數進行抽樣,這個函數會返回一個隨機值

SELECT * FROM numbers TABLESAMPLE(BUCKET 3 OUT OF 10 ON number) s;<---------- 按照指定的列而非rand()函數進行分桶的話,那麼同一語句屢次執行的返回值是相同的
SELECT * FROM numbers TABLESAMPLE(BUCKET 3 OUT OF 10 ON number) s;
SELECT * FROM numbers TABLESAMPLE(BUCKET 5 OUT OF 10 ON number) s;
SELECT * FROM numbers TABLESAMPLE(BUCKET 5 OUT OF 10 ON number) s;

SELECT * FROM numbers TABLESAMPLE(BUCKET 1 OUT OF 2 ON number) s;<---------- 分桶語句中的分母表示的是數據將會被散列的桶的個數,而分子表示將會選擇的哪一個桶
SELECT * FROM numbers TABLESAMPLE(BUCKET 2 OUT OF 2 ON number) s;

----------數據塊抽樣 <---------- Hive提供了按照抽樣百分比進行抽樣的方式,這種事基於行數的,按照輸入路經下的數據塊百分比進行的抽樣
SELECT * FROM numbersflat TABLESAMPLE(0.1 PERCENT) s;<---------- 這種抽樣方式不必定適合全部的文件格式,另外,這種抽樣的最小抽樣單元是一個HDFS數據塊,若是表的大小小於普通的塊大小128M的話,那麼就會返回全部行
set hive.sample.seednumber=0.2;<---------- 基於百分比的抽樣方式提供了一個變量,用於控制基於數據塊的調優的種子信息

SELECT * FROM numbersflat WHERE number % 2 =0;<---------- 抽樣會掃描表中全部的數據,而後在每N行中抽取一行數據。
CREATE TABLE numbers_bucketed(number int)
CLUSTERED BY (number) INTO 3 BUCKETS;<---------- 根據字段number建立分桶表,將數據放入3個分桶中
set hive.enforce.bucketing = true; <---------- 強制分桶處理
INSERT OVERWRITE TABLE numbers_bucketed SELECT number FROM numbers;<---------- 將表numbers的數據insert到分桶表
DESCRIBE EXTENDED numbers_bucketed;
dfs -ls hdfs://Master.hadoop:9000/data/hive/warehouse/guoyongrong.db/numbers_bucketed;<---------- 查看錶數據所在的目錄
dfs -cat hdfs://Master.hadoop:9000/data/hive/warehouse/guoyongrong.db/numbers_bucketed/000001_0;<---------- 查看錶數據所在的目錄下的文件信息

SELECT * FROM numbers_bucketed TABLESAMPLE ( BUCKET 2 OUT OF 3 ON number) s;<---------- 高效的僅僅對其中一個數據桶進行抽樣

----------UNION ALL
SELECT log.ymd,log.level,log.message
FROM
(
SELECT l1.ymd,l1.level,l1.message,'log1' AS source
FROM log1 l1
UNION ALL <---------- 將2個以上的表進行合併,每一個union字查詢都必須具備相同的列並且對應的每一個字段類型必須是一致的。
SELECT l2.ymd,l2.level,l2.message,'log2' AS source
FROM log2 l2
) log
SORT BY log.ymd ASC;

FROM( FROM src SELECT src.key,src.value WHERE src.key < 100 UNION ALL <---------- 這個查詢將會對同一分源數據進行屢次拷貝分發 FROM src SELECT src.key,src.value WHERE src.key > 110) unioninputINSERT OVERWRITE DIRECTORY '/tmp/union.out' SELECT unioninput.*;

相關文章
相關標籤/搜索