// 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.*;