Hive笔记

一、Hive是基于Hadoop的数据仓库。
1、计算
把HQL查询通过HQL解析引擎转换为一系列在Hadoop集群上运行的MapReduce作业,易于分析。
 解释器、编译器、优化器完成HQL查询语句从词法分析、语法分析,编译生成执行计划,优化查询计划的生成。生成的查询计划存储在HDFS中,并在随后由MapReduce执行。具体过程是:HQL->AST Tree->QueryBlock->OperatorTree->逻辑层优化->翻译成MR任务->物理层优化生成最终执行计划
2、数据
把数据组织为表,通过这种方式为存储在HDFS的数据赋予结构,hive中一个表对应于hdfs上一个文件夹。默认在/user/hive/warehouse/下
元数据存储在metastore数据库(支持derby默认、mysql、oracle)中。元数据包括表名、列和分区及其属性、表属性、表数据的目录等

 

3、HQL转换成MR的过程
HQL->AST Tree->QueryBlock->OperatorTree->逻辑层优化->翻译成MR任务->物理层优化生成最终执行计划
  • Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree
    • 子查询或某表生成TOK_FROM节点
    • 每个表生成TOK_TABREF节点
    • join条件生成TOK_JOIN节点,并在 = 子节点处标记关联条件
  • 遍历AST Tree,抽象出查询的基本组成单元QueryBlock
  • 遍历QueryBlock,翻译为执行操作树OperatorTree
    • 基本:SelectOperator,TableScanOperator,FilterOperator,JoinOperator,GroupByOperator,ReduceSinkOperator
    • ReduceSinkOperator 在Map阶段将字段组合序列化为Reduce Key/value, Partition Key,同时也标志着Hive生成的MR程序中Map阶段的结束
  • 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量
    • MapJoinProcessor 优化mapjoin
    • BucketMapJoinOptimizer 优化bucket mapjoin
    • GroupByOptimizer 优化map端聚合
  • 遍历OperatorTree,翻译为MapReduce任务
  • 物理层优化器进行MapReduce任务的变换,生成最终的执行计划
    • CommonJoinResolver + MapJoinResolver mapjoin优化器
二、配置:
  • Hive中,所有的默认配置都在${HIVE_HOME}/conf/hive-default.xml文件中,如果需要对默认的配置进行修改,可以创建一个hive-site.xml文件,放在${HIVE_HOME}/conf目录下。里面可以对一些配置进行个性化设定。永久有效
  • hive -hiveconf 属性名=属性值,只对本次启动的会话有效(hive -hiveconf fs.default.name=localhost:9000 -hiveconf mapred.job.tracker=localhost:9001)
  • hive>set 属性名=属性值; 只对本次会话有效
    • hive>SET -v; 查看当前设定的所有信息
  • ${HOME}/.hiverc 配置一系列的set语句,hive启动时会自动生效,注意要加;
hive>SET mapred.job.tracker=Hmaster:9001 设置参数 
hive>SET mapred.job.tracker 显示参数值
SET命令设置的参数的作用域是Session级的,只对本次会话的操作有用。
优先级依次提高。
注意一定要在metastore同级目录下执行hive或beeline,否则会报未初始化metastore错误
设置最大内存:hive-config.sh export HADOOP_HEAPSIZE=${HADOOP_HEAPSIZE:-512} (默认是256M)即使调大机器内存也是无用的,必须在此处配置hive JVM最大内存值
(3)常用配置
属性名
默认值
 
hive.cli.print.header
false
显示列名
hive.cli.print.current.db
false
显示当前库名
hive.mappred.mode
nonstrict
是否严格模式(建议strict,这样对分区表查询时,必须在where条件里过滤分区)
hive.root.logger
 
日志级别(设置为INFO,console即在当前窗口显示,只能通过-hiveconf生效)
hive.enforce.bucketing
false
导入数据前设置使强制用桶对数据进行划分(2.x移除,总是true)
hive.optimize.bucketmapjoin
false
使用桶优化map join
hive.enforce.bucketmapjoin
false
启用分桶map-side join
hive.cbo.enable
false(0.x) true(1.1.0+)
启用cbo
mapred.child.java.opts
修改hive内存限制
hive.msck.path.validation
 
默认当发现分区目录有非法字符时会报错,skip自动跳过异常分区,ignore则尝试创建此分区
set mapred.job.queue.name=queue3;
set mapreduce.job.queuename=queue3;
set mapred.queue.names=queue3;
 
设置资源池
(4)常用命令
show  functions;   #查看函数
show  functions  'xpath.*';   #正则查看函数名
describe function xpath;  #查看具体函数内容
show partitions 表名; 显示这个表的分区情况
explain sql;    查看Hive的执行计划
explain extended sql;    查看Hive更详细的执行计划
desc t1; 查看表结构
describe extended t1;    显示一个表的详细情况
 show tables;    #查看所有表名
 show tables  'ad*'    #查看以'ad'开头的表名
set 命令    #设置变量与查看变量;
set-v    #查看所有的变量
set hive.stats.atomic    #查看hive.stats.atomic变量
set hive.stats.atomic=false #设置hive.stats.atomic变量
set hivevar:变量名=变量值 #设置自定义变量
 dfs  -ls #查看hadoop所有文件路径
 dfs  -ls /user/hive/warehouse/ #查看hive所有文件
 dfs  -ls /user/hive/warehouse/ptest #查看ptest文件
 source file #在client里执行一个hive脚本文件
 quit #退出交互式shell
exit #退出交互式shell
 reset #重置配置为默认值
 !ls #从Hive shell执行一个shell命令
(5)启动
  • 命令行
    • hive 或 hive --service cli
      • -e: 命令行sql语句
-f: SQL文件
-h, --help: 帮助
--hiveconf: 指定配置文件-i: 初始化文件
-S, --silent: 静态模式(不将错误输出)-v,--verbose: 详细模式
    • beeline(推荐)
      • 连接:(注意这个连的是metastore,无论是存在于derby还是mysql,metastore服务的端口都是10000,此处的数据库是填的hive库,第一次只能填default)
  • !connect jdbc:hive2:// 默认连localhost的10000端口的default库
  • !connect jdbc:hive2://namenode-ip:10000/dbName  dbName若不写则默认是default库
  • beeline -u jdbc:hive2://localhost:10000 -n root
  • hive.server2.enable.doAs设为true后,自动模拟当前用户的kerberos cache认证的用户
    • beeline -u "jdbc:hive2://host:10000/default;principal=hive/host@REALM"
  • 指定用户模拟
    • beeline -u 'jdbc:hive2://fuxi-luoge-76:36003/default;principal=hive/_HOST@FUXI-LUOGE-79;hive.server2.proxy.user=XXXXXXX'
(连接后需要输入用户名和密码,在hive-site中的javax.jdo.option.ConnectionUserName、javax.jdo.option.ConnectionPassword有设置)
(连接后若报User root is not allowed to impersonate anonymous,在core-site.xml中配置hadoop.proxyuser.root.hosts的value为*,hadoop.proxyuser.root.groups的value为*)
  • web界面 hive --service hwi &
  • metastore服务 nohup hive --service metastore > metastore.log 2>&1 &
  • hive作为后台服务供远程使用(端口号10000)
    • hive --service hiveserver2 &
    • nohup hiveserver2 > hiveserver2.log 2>&1 &
    • 可通过配置hive-stie.xml实现高可用
      • hive.server2.support.dynamic.service.discovery true
      • hive.server2.zookeeper.namespace hiveserver2_zk
      • hive.zookeeper.quorum zkNode1:2181,zkNode2:2181,zkNode3:2181
      • hive.zookeeper.client.port 2181
      • hive.server2.thrift.bind.host 0.0.0.0
      • hive.server2.thrift.port 10001
三、本地模式
set mapred.job.tracker=local; 若设置成local,则会在本地执行mapreduce任务,对小数据集查询的运行非常有用。小任务在集群运行时反而效率会低
set hive.exec.mode.local.auto=enable;  设置本地自动执行mapreduce,默认为关闭。若设为enable,则Hive会先分析查询中的每个任务,当任务的输入规模小于hive.exec.mode.local.auto.inputbytes.max属性值(默认为128MB),并且全部的map数少于hive.exec.mode.local.auto.task.max值(默认为4),全部的reduce数为1或0时,则任务自动在本地模式执行
四、错误日志
Hive使用Log4j记录日志。默认情况下,记录级别是WARN,存储在HDFS:/tmp/hive/安装hive的用户名/hive.log。
若要在终端看到日志内容,可用(只能用-hiveconf配置):
hive -hiveconf hive.root.logger=INFO,console
五、Metastore
是Hive元数据的集中存放地。包括两部分:服务和后台数据的存储。
默认情况:内嵌metastore配置,metastore与hive运行在同一个JVM中,包含一个内嵌的以本地磁盘为存储的Derby数据库实例。比较简单,但缺点是不支持多会话。多用于测试环境
本地metastore:虽然metastore与hive在同一个进程中,但连接的却是在另一个进程中运行的数据库(如Mysql),支持多会话
远程metastore:metastore与hive运行在不同的进程,数据库层可以完全置于防火墙后,更加安全和可管理。多用于生产环境
六、HiveQL 对象、DDL
HiveQL是一种类似SQL的语言, 它与大部分的SQL语法兼容, 但是并不完全支持SQL标准, 如HiveQL不支持更新操作, 这是因其底层依赖于Hadoop云平台这一特性决定的, 但其有些特点是SQL所无法企及的。例如多表查询、支持CTAS和集成MapReduce脚本等
1、类型
  • 基本类型
整数(有符号):TINYINT(1)    SMALLINT(2)    INT(4)    BIGINT(8)
浮点数:FLOAT(4)    DOUBLE(8)    DECIMAL
BOOLEAN:TRUE    FALSE
文本:STRING(变长)    VARCHAR(0.12.0开始支持)    CHAR(0.13.0开始)
二进制:BINARY(变长)
时间:TIMESTAMP(精度为纳秒,自1970年以来的偏移量)、DATE(0.12.0开始支持)
  • 复杂类型
类型
含义
定义
使用
显示
ARRAY
数组,一组相同类型的元素
array
字段名[0]
["a","b","c"]
MAP
字典,由键值对组成
map<string,int>
字段名[key]
{"a":1,"b":2,"c":3}
STRUCT
结构,包含不同类型的元素
struct<fa:string,fb:int>
字段名.fa
{"fa":1}
数组字典
字典的value是数组
map<int,array>
 
{1:["a","b"],2:["c","d"]}
  • 类型转换
所有整数类型、FLOAT、STRING都能隐式转换为DOUBLE,TIMESTAMP可以被隐式转换为STRING,BOOLEAN不能转换为其他任何数据类型。显式类型转换得用CAST,若强制转换失败后会返回NULL,如SELECT CAST('1' AS INT);
  • 注意
    • 当int型溢出时,插入到parquet表里是空值,需要设成bigint型。建议能用bigint就别用int
2、函数
SHOW FUNCTIONS; 获取函数列表
DESCRIBE FUNCTION 函数名; 获取某个特定函数的帮助
create function 创建函数
3、表
加载数据到托管表时,hive并不判断数据是否满足表的模式,只是单纯的文件移动,因此很快。只有在查询的时候才会检查模式。即读模式。
hive只能读取hdfs的数据,但本地数据可以load进hdfs
(1)表类型
  • 托管/内部表(创建时会将数据移到数据仓库指向的路径,若local load则保留原文件,若hdfs load则不保留原文件;删除时删元数据、数据)
create table managed_table(dummy STRING);
load data inpath '/user/tom/data.txt' into table managed_table;  --加载hdfs文件追加到原表
load data local inpath '/home/hadoop/test_data/temper.dat' overwrite into table testsort;  --加载本地文件覆盖原表
  • 外部表(创建时仅在hdfs location创建空目录,location只能指定hdfs文件,不需要load)
  • 创建
    • create external table external_table(dummy STRING) row format delimited fields terminated by ',' location '/user/tom/external_table';
            然后直接就可以查了,至于能否查出来得看数据是否匹配模式(location后面跟的必须是数据所在目录)
修改location
alter table external1 set location '...';
    • 情况
      • 删除外部表时只删元数据,外部数据没有任何变化
      • 无论是内部表还是外部表,无非就是往对应的hdfs目录复制文件,再以定义的表结构来读取数据
      • 重命名时只改表名,外部数据目录名、内容没有任何变化
      • 建同构表create table like时,仍然建的是内部表
  • 分区外部表
    • create EXTERNAL table IF NOT EXISTS outer_table (userid string) partitioned by (ptDate string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' location '/user/tom/outer_table';
    • alter table test add partition (ptDate=20121214) location '/user/tom/outer_table/20121214'; (必须加分区,才能传文件到hdfs)
  • 分区表(注意分区列是排在其他列后面的。且overwrite是分分区的)
            create table logs (ts BIGINT,line STRING) partitioned by (dt STRING,country STRING) row format delimited fields terminated by ' ';
  • 加载数据到数据表时,要显式指定分区值
                    load data local inpath '/home/hadoop/test_data/stu.dat' into table logs partition (dt='2016-08-15',country='CN');
                    insert into part_stu partition(sex='M') select name,id from stu where sex='M';
  • 查询,使用where分区列,注意:查询出来的分区列数据是从hdfs目录获得的
                    select * from part_stu where sex='M';
  • 当hdfs上有分区数据时,若未add partition,分区外部表也无法识别,必须add partition,且分区目录在表的location后,可不用指定location
alter table t1 add partition (ds='2019-01-09');
    • 动态分区(自动根据数据创建分区,注意load不支持动态分区装载,只能用insert)
                    set hive.exec.dynamic.partition=true;  --启用动态分区
                    insert into part_stu2 partition(sex='M',id) select name,id from stu where sex='M';(sex静态分区,id动态分区)
                    set hive.exec.dynamic.partition.mode=nonstrict; 
                    --启用非严格动态分区,即允许所有分区列都是动态分区。默认主分区不能是动态分区
                    insert into part_stu partition(id,sex) select name,id,sex from stu;
0
  • 桶表(类似于Oracle的聚簇表,大表化多个小表,方便map-side join)
create table bucketed_users (id INT,name STRING) clustered by (id) sorted by (name asc) into 4 buckets;
set hive.enforce.bucketing=true;(除2.x之外都必须设置,否则按桶分数据无效)
insert overwrite table bucketed_users select * from t2; (若使用load导入数据,桶分数据也是无效的)
set hive.optimize.bucketmapjoin=true;(启用按桶map join)
select /*+mapjoin(a)*/ count(*) from bucketed_users a join bucketed_users b on a.id = b.id;
物理上,每个桶就是一个文件,桶数和reduce任务个数相同(可强制指定)。Hive对值进行哈希并将结果除以桶的个数取余数来划分桶。防止热块
取样:select * from bucketed_users tablesample(bucket 1 out of 4 on id); 将所有桶分成4份,取1份
TABLESAMPLE(BUCKET x OUT OF y on col)
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了64份,当y=32时,抽取(64/32=)2个bucket的数据,当y=128时,抽取(64/128=)1/2个bucket的数据。x表示从哪个bucket开始抽取。例如,table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。
随机采样:select * from t1 where rand()<=0.001 distribute by rand() sort by rand() limit 1000; (0.001是采样数占总数的比例*100)
(2)修改表
由于hive是读时模式,只有在读取数据的时候才会检查表结构是否满足数据需要,因此可以非常灵活地变更元数据以符合新数据的结构
  • 重命名 alter table t32 rename to t;
  • 保留表结构,删除数据 dfs -rmr 表数据文件目录    或  create table t2 like t;
  • 增加分区:alter table tp2 add partition(dt='2016-07-04',country='cn');   alter table tp1 add partition(ds='N') location '/tp1/ds=N'; (注意ds必须是分区列)
  • 删除分区:alter table tp2 drop partition(dt='2016-07-04',country='cn'); alter table tp1 drop partition (ds='N');
  • 修改分区路径 alter table tp1 partition(ds='M') set location '/tp1/ds=M';(不会删旧目录和数据,也不移动数据)
  • 重命名表:alter table tp2 rename to tp3;
  • 改变列名、类型、注释、位置:alter table tp2 change column ip ipv4 string comment 'comment1:ipv4' after userid;  (after userid可以换成first,即放在首列)
  • 增加/替换列:alter table tp2 add/replace columns (列名 列类型, ...)   add columns允许在当前列的末尾、分区列之前增加新的列,replace columns删除当前列,加入新列。  
alter table tp2 add columns (ipv6 string);
  • 删除列: alter table tp2 replace columns (新schema);
  • 增加表属性:alter table tp2 set TBLPROPERTIES table_properties
                                 table_properties:{property_name=property_value,property_name=property_value,...}
  • desc extended tp2; 获得表的metadata信息
  • 改变文件格式和组织:alter table tp2 set FILEFORMAT ...    alter table tp2 clustered by (col1,col2...) [sorted by (col1,...)] into buckets数 buckets;
读时模式(hive):
只有在读的时候hive才检查、解析具体的 数据字段、schema。
优势是load data 非常迅速,因为它不需要读取数据进行解析,仅仅进行文件的复制或者移动。
写时模式(传统数据库):
优势是提升了查询性能,因为预先解析之后可以对列建立索引,并压缩,但这样也会花费要多的加载时间。 
4、视图(只有元数据,在hdfs上无对应目录。视图是只读的。若基本表被删除或无效,则视图的查询也将无效)
类似rdbms的view,不存储实际数据
 create view v1 as select * from t4 where t4.id=1;
create view v_mapcity(icity,iprovince) as select cols['city'],cols['province'] from ext_mapcity where cols['city']='hangzhou';
5、数据库
hive中的数据库含义类似于mysql,是命名空间或表的集合。初始化元数据后自动产生一个默认的数据库default
  • 创建数据库:CREATE DATABASE|SCHEMA [IF NOT EXISTS] dbName
    • create database test location '/tmp/dir'; 使用特定目录,而非/user/hive/warehouse子目录
  • 列出数据库:SHOW DATABASES;
  • 切换数据库:USE dbName;
  • 删除数据库:DROP (DATABASE|SCHEMA) [IF EXISTS] dbName [RESTRICT|CASCADE];
  • cascade:删除数据库先把其中的表删掉
七、存储格式
行格式:行和一行中的字段如何存储,由SerDe定义(序列化和反序列化工具) row format
文件格式:一行中字段容器的格式,最简单的格式是纯文本文件 file format
(1)行格式  ROW FORMAT
  • DELIMITED(使用分隔符)
行内分隔符fields:Ctrl+A
集合元素分隔符collection items:Ctrl+B
键值分隔符map keys:Ctrl+C
行间分隔符lines:换行符
create table testsort(year int,temper int) row format delimited 
fields terminated by '\001'
collection items terminated by '\002'
map keys terminated by '\003'
lines terminated by '\n';
  • SERDE(使用SerDe)
csv文件,文件字段用引号括住,字段间用逗号分隔,不支持字段内有换行符的情况
CREATE external TABLE default.pyq_message (
`ID` string ,
`RoleId` string ,
`TargetId` string COMMENT '留言对象ID',
`ReplyId` string COMMENT '回复对象ID',
`OwnerId` string COMMENT '空间主人ID',
`Text` string COMMENT '留言内容',
`CreateTime` string ,
`Status` string COMMENT '留言状态:0 未读 1 已读 -1已删除'
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
"separatorChar" = ",",
"quoteChar" = "\"",
"escapeChar" = "\\"
)
location '/user/liyubin/pyq_message';
 
(2)二进制存储格式 STORED AS
Textfile、Sequencefile、Avro、RCFile
  • Sequencefile 可分割(文件可划分成块)、可压缩、面向行。
    • 提供了三种压缩方式:NONE、RECORD、BLOCK(BLOCK方式可分割且压缩性能最好),配置方式:set mapred.output.compression.type=BLOCK
  • Avro 可分割、可压缩、面向行、支持模式演化及多种编程语言的绑定。Hive可以使用avroSerDe读取或写入Avro文件
  • RCFile Parquet 可分割、可压缩、面向列。按列记录文件,表的每个行分片依次存表的每一列数据(推荐)
    • 适合场景:列很多且一般只用到某些列;列有很多重复数据
create table compressed_users(id INT,name STRING) stored as sequencefile;
(3)压缩(hive会自动根据文件后缀名进行解压缩)
0
压缩率:Bzip2>Gzip>LZO/Snappy
Bzip2和LZO提供块级压缩,可分割。Gzip和Snappy不提供块级压缩,不可分割
可在hadoop或hive中配置,只需要配置一个
  • hadoop
    • 压缩器 set io.compression.codecs="org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.LzoCodec";
    • 中间压缩(DefaultCodec、GzipCodec、Bzip2Codec、SnappyCodec、LzoCodec)
      • 开启 set mapred.compress.map.output=true
      • 指定 set mapred.map.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
    • 结果压缩
      • 开启 set mapred.output.compress=true;
      • 指定 set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
  • hive
    • 中间压缩 (推荐LZO)
      • 开启 set hive.exec.compress.intermediate=true;
      • 指定 set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
    • 结果压缩
      • 开启 set hive.exec.compress.output=true;
      • 指定 set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
普遍案例:
create table t1_compress (...) stored as XXX; (XXX有TEXTFILE、SEQUENCEFILE、RCFILE、AVRO)
set hive.exec.compress.output=true;
set mapred.output.compress=true;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.XXXCodec; (XXX有Default、Bzip2、Gzip、Lzo2、Snappy)
insert overwrite into table t1_compress select * from t1;
 
create table t1_compress (...) stored as ORCFILE TBLPROPERTIES ("orc.compress"="XXX") (XXX有ZLIB、SNAPPY)
 
查看.gz文件:/bin/zcat /user/hive/warehouse/final_comp_on_gzip/000000_0.gz
查看sequencefile文件:hadoop fs -text /user/hive/warehouse/final_comp_on_gz_seq/000000_0
一般使用方法:中间压缩使用SnappyCodec,结果压缩使用Bzip2,文件格式用sequencefile
效果:
[numFiles=1, numRows=4312, totalSize=420, rawDataSize=21564]
(4)存档
配置:
set hive.archive.enabled=true;
set hive.archive.har.parentdir.settable=true;
set har.partfile.size=1099511627776;
命令:
alter table t1 archive partition (p1='v1');
alter table t1 unarchive partition (p1='v1');
八、导入数据
(1)INSERT
不支持行级DML数据
  • 写入表
  • 覆盖表 insert overwrite table target select c1,c2 from source;
  • 增量添加 insert into table target select c1,c2 from source;
  • 覆盖分区 insert overwrite table target partition(dt='2001-01-01' ) select c1,c2 from source;
  • 动态分区插入 insert overwrite table target partition(dt) select c1,c2,dt from source;
  • 写入文件系统
    • INSERT [OVERWRITE] [LOCAL] DIRECTORY d1 select ... from ...
    • 写入文件系统时,每列用^A区分,换行表示一行数据结束。如果任何一列不是原始类型,则这些列被序列化为JSON格式。
  • 多表插入
    • from source insert overwrite table t1 select year,count(distinct station) group by year insert into t2 select year,count(1) group by year;
(2)CTAS(不支持外部表)
create table t32 as select * from t3;
(3)Load (路径是文件时只加载此文件,是目录时加载目录下的所有文件。且加载时文件会移动到hadoop默认表目录下)
load data [local] inpath 'filepath'  [overwrite] into table tablename [partition (partcol1=val1,partcol2=val2 ...)]
LOCAL关键字:在本地文件系统查找filepath
OVERWRITE关键字:删除目标表的内容,再添加filepath新内容
注意partition子句指定了分区列的值,而不会对源数据有任何筛选,且会改变导入后分区列的值
(4)Sqoop
注意:hive将数据写入hdfs时,会自动把字符集转为utf-8,若源数据不是utf-8会出现乱码,因此要先将源数据转为utf-8字符集再加载
十、查询数据
(1)排序
order by(全局排序,单机执行从而效率低,在严格模式下需要加limit):
    select * from students order by id desc;
    select * from testsort distribute by year sort by year asc,temper desc;
distribute by key sort by col(distribute对key hash分组到reducer,sort局部排序,按组有序而全局无效)
cluster by key(相当于distribute by key sort by key asc)
(2)连接
内连接  select t4.*,t5.* from t4 join t5 on (t4.id=t5.id);
外连接(left outer join/right outer join/full outer join)   select t4.*,t5.* from t4 left outer join t5 on (t4.id=t5.id);
半连接(类似于IN) select * from t4 left semi join t5 on (t4.id=t5.id);
map连接(把指定的表放入mapper内存中执行连接操作,小表放入内存)     select /*+mapjoin(t4)*/ t4.*,t5.* from t4 join t5 on (t4.id=t5.id);
(3)子查询
Hive只允许子查询出现在select语句的from子句或in子句中。
  • from子句。要加别名
  • in子句。不支持嵌套in子查询
(4)限制返回结果数
select * from stu limit 5;
(5)合并结果集
union all
(6)显式类型转换
cast(col as FLOAT)
转换BINARY:Hive只支持BINARY转换成String,若要转换成其他类型需要通过嵌套cast()的方式
(7)抽样查询
tablesample(bucket x out of y on col)  数据值抽样。将数据按col的hash值分成y个桶,再抽样其中的x个(也适用于非分桶表。但在分桶表中抽样查询时,只会扫描涉及到的桶下的数据,提高了效率)
tablesample(x percent) 数据块抽样。抽样的最小样本单元是一个HDFS数据块,若表的数据大小小于128M,则不管x是多少,都会返回所有结果
(8)判断
case ... when ... then ... end
(9)streaming(可用shell、python,类比java开发UDF,但要简单得多)
transform(col1,col2...) using '/bin/ | python ...' as (col3,col4...)
注意出现transform时,select不能有别的列,只能有transform
脚本执行: source HQL脚本文件;
  • shell
    • cat命令 from invites a insert overwrite table events select transform(a.foo,a.bar) using '/bin/cat' as (oof,rab) where a.ds>'2010-08-09';
  • python
    • SELECT TRANSFORM(pv) USING 'python /root/script/sum.py' AS total FROM tsum;
(10)分区列
当分区列的值是1、2、3时,不要用'1'、'2'、'3'查
 
SELECT [ALL | DISTINCT] select_expr,select_expr,...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list] ]
[LIMIT number];
  • Top-k   select * from t1 sort by amount desc limit 5;
  • HAVING(Hive使用子查询实现)  select col1 from (select col1,sum(col2) as col2sum from t1 group by col1) t2 where t2.col2sum>10;  (sql形式为:select col1 from t1 group by col1 having count(1)>10)
(11)去重计数
count(distinct xxx)
若要符合某些条件才计入总数,则要将不符合条件的设置为null,再进行count distinct
count(distinct case when xxx then yyy else null end)
(12)count
count(*):所有行进行统计,包括NULL行 count(1):所有行进行统计,包括NULL行 count(column):对column中非NULL进行统计 count(distinct column):对column中非NULL进行去重统计 count(distinct col1,col2,...):对col1、col2,...多个字段同时去重并统计。 count(CASE WHEN plat=1 THEN u ELSE NULL END), count(DISTINCT CASE WHEN plat=1 THEN u ELSE NULL END), count(CASE WHEN (type=2 OR type=6) THEN u ELSE NULL END), count(DISTINCT CASE WHEN (type=2 OR type=6) THEN u ELSE NULL END)
十二、UDF(用户自定义函数)
(1)UDF必须用Java语言编写
UDF:作用于单个数据行,且产生一个数据行作为输出。如数学函数、字符串函数
UDAF:接受多个输入数据行,且产生一个输出数据行。如count、max
UDTF:作用于单个数据行,且产生多个输出数据行。如表
(2)Hive UDF必须满足下面两个条件:
必须是org.apache.hadoop.hive.ql.exec.UDF的子类
必须至少实现了evaluate()方法
(3)在hive中使用UDF:
两种方法:
会话设置:
注册:add jar /home/hadoop/jar/Strip.jar
建函数:create temporary function Strip as 'com.lyb.hive.Strip';  (temporary表示此UDF只是为这个Hive会话定义的,as后需要跟包名.类名,UDF名不是大小写敏感的)
全局设置:
hive --auxpath jar包路径
或者hive运行前在hive-env.sh 设置HIVE_AUX_JARS_PATH
十四、索引
1、Hive的2维坐标结构:定位行键->列修饰符
对比:HBase的4维坐标结构:定位行键->列簇->列修饰符->时间戳
2、创建索引
  • 创建普通索引
    create index idx_sogou_content on table sogou(content)
    as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
    with deferred rebuild
    in table sogou_idx_table;
  • 创建BITMAP索引
3、删除索引(会自动删掉索引表)
    drop index idx_sogou_content on sogou;
4、重建索引
    alter index idx_sogou_content on sogou rebuild;
5、查看索引
    show index on sogou;
6、优化参数
    set hive.optimize.index.filter=true;
    set hive.optimize.index.groupby=true;
    必须开启这两个参数,索引才能起作用
十五、Hive优化
  • 列裁剪  只读取查询中需要用到的列
  • set hive.optimize.cp=true; (默认true,0.13.0移除)
  • 分区裁剪  查询过程中只读取涉及到的分区,where。
  • Join操作 
  • 将条目少的表/子查询放在join左边(在Join操作的Reduce阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 OOM 错误的几率)
  • MR任务数量和join的连接条件数目是一样的(即使有多个join,但连接条件都是id,也只有一个MR任务)
  • map-join操作 
  • 无须shuffle、reduce操作join就可以在map阶段全部完成。
  • insert overwrite table t1 select /*+mapjoin(pv)*/ pv.pageid,u.age from page_view pv join user u on (pv.userid=u.userid);
    • 适用场景:指定进行mapjoin的表能一次加载进内存
    • 参数
  • hive.join.emit.interval = 1000
  • hive.mapjoin.size.key = 10000
  • hive.mapjoin.cache.numrows = 10000
    • 自动优化:Hive版本0.11之后,Hive默认启动该优化,也就是不再需要显式的使用MAPJOIN标记,其会在必要的时候触发该优化操作将普通JOIN转换成MapJoin
    • hive.auto.convert.join 开启自动map-join优化
    • hive.mapjoin.smalltable.filesize 单位是字节,默认25M,指定使用该优化的表的最大大小,小于此值的表会被加载进内存
    • 不支持场景:右外连接、全外连接
  • 分桶表自动优化
    • 适用条件:数据按连接键分桶,其中一张表的分桶个数必须是另一张表的若干倍
    • hive.optimize.bucketmapjoin=true 开启分桶map-join优化
    • sort-merge-join优化:效率更高,要求也更高
      • 适用条件:数据按连接键分桶并排序,涉及所有表具有相同的分桶数
      • hive.input.format = org.apache.hive.ql.io.bucketizedhiveinputformat;
      • hive.optimize.bucketmapjoin.sortedmerge = true
      • hive.optimize.bucketmapjoin = true
  • group by 操作
  • map 端部分聚合: 并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果(是基于hash进行聚合的)
  • hive.map.aggr = true 是否在map 端进行聚合,默认为 True
  • hive.groupby.mapaggr.checkinterval = 100000 在map 端进行聚合操作的条目数目
    • 数据倾斜时进行负载均衡
  • hive.groupby.skewindata = true 有数据倾斜的时候进行负载均衡,默认false。当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中(不按key分布到reduce),每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
  • 合并小文件
  • 文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响
  • 参数:
  • hive.merge.mapfiles = true 是否合并 Map 输出文件,默认为 True(当只有select或mapjoin时,设为false可避免对map输出的文件的扫描,提高效率)
  • hive.merge.mapredfiles = false 是否合并 Reduce 输出文件,默认为 False
  • hive.merge.size.per.task = 256*1000*1000 合并文件的大小
  • map阶段优化(确定合适的map任务数)
  • map任务数=总数据量/每个map任务的数据量,注意,直接设置mapred.map.tasks是无效的
  • 每个map任务的数据量=[$(mapred.min.split.size),min($(dfs.block.size),$(mapred.max.split.size))]
  • mapred.min.split.size: 指的是数据的最小分割单元大小;min的默认值是1B
  • mapred.max.split.size: 指的是数据的最大分割单元大小;max的默认值是256MB
  • dfs.block.size: 指的是HDFS设置的数据块大小。已经指定好的值,而且这个参数默认情况下hive是识别不到的
  • reduce阶段优化(确定合适的reduce任务数)
    • 可直接设置mapred.reduce.tasks,有效,默认-1,即不限制
    • min(${hive.exec.reducers.max},(${input.size}/${hive.exec.reducers.bytes.per.reducer}))
    • hive.exec.reducers.max:此参数从Hive 0.2.0开始引入。在Hive 0.14.0版本之前默认值是999;而从Hive 0.14.0开始,默认值变成了1009,这个参数的含义是最多启动的Reduce个数
    • hive.exec.reducers.bytes.per.reducer:此参数从Hive 0.2.0开始引入。在Hive 0.14.0版本之前默认值是1G(1,000,000,000);而从Hive 0.14.0开始,默认值变成了256M(256,000,000),可以参见HIVE-7158和HIVE-7917。这个参数的含义是每个Reduce处理的字节数。比如输入文件的大小是1GB,那么会启动4个Reduce来处理数据。
  • order by limit优化
    • sort by limit 外面套一层 order by limit (局部排序后再取多个前N,整体排序)
  • 随机采样
    • select * from t1 where rand()<=0.001 distribute by rand() sort by rand() limit 1000; (0.001是采样数占总数的比例*100)
  • sql角度优化
  • 无效ID在关联时的数据倾斜
  • 两种解决方法:
    • 空数据不参与关联 union all 空数据
    • left outer join关联条件:case when a.id is null then concat('dp_hive',rand()) else a.id end = b.id(更好)
  • t1(key数据倾斜) join t2
    • t1每个key都加上随机前缀(如不大于N的整数1,2,...,N),t2每条数据扩容N倍,扩容出来的数据每条都加上1,2,...,N前缀,再进行join关联,关联后再去掉前缀
十六、常用函数
1、时间(以下string型日期必须满足格式才行)
符合日期格式要求的字符串可以直接比较,不需要转换格式
string to_date(arg) 
日期时间转成时间(arg的格式必须是xxxx-x(x)-x(x) xx:xx:xx,结果是xxxx-xx-xx)
bigint unix_timestamp() 
获取当前unix时间戳
bigint unix_timestamp(string date,string pattern)
将pattern格式的date转换为unix时间戳
string from_unixtime(bigint arg,string pattern)
将arg时间戳转换为pattern形式的时间
int datediff(string enddate, string startdate)
结束日期减去开始日期的天数(和时间部分没有关系,只是日期相减,如10.22-9.29是23天)
string date_add(string startdate, int days)
开始日期startdate增加days天后的日期,date格式是xxxx-xx-xx
string date_sub (string startdate, int days)
开始日期startdate减去days天后的日期,date格式是xxxx-xx-xx
int year(string date)
年份
int month(string date)
月份
int day(string date)
int hour(string date)
int minute(string date)
int second(string date)
int weekofyear (string date)
2、窗口分析函数
可以不和group by合用,但注意在和group by合用时,分析函数里只能出现group by的字段;在和distinct合用时,分析函数只能出现group by的字段
 NTILE(num)  over 
([partition_clause]  order_by_clause)
把有序的数据集合 平均分配 到 指定的数量(num)个桶中, 将桶号分配给每一行。如果不能平均分配,则优先分配较小编号的桶,并且各个桶中能放的行数最多相差1。然后可以根据桶号,选取前或后 n分之几的数据。
用于等级、百分点、n分片等
RANK/DENSE_RANK/ROW_NUMBER()  over  (partion  by  col1...  order  by  col2...  desc/asc)
rank  会对相同数值,输出相同的序号,而且下一个序号不间断;
dense_rank  会对相同数值,输出相同的序号,但下一个序号,间断 
row_number 会对所有数值输出不同的序号,序号唯一连续;
用于组内排序编号
LAG/LEAD(col,n,DEFAULT) over  
(partion  by  col1...  order  by  col2...  desc/asc)
lag 返回窗口内往上第n行值,若null则default
lead 返回窗口内往下第n行值,若null则default
用于组内排序后,取当前行的值前第n个或后第n个值
 FIRST_VALUE/LAST_VALUE(col)  over ([partition_clause]  order_by_clause)
first_value:  取分组内排序后,截止到当前行,第一个值
last_value:  取分组内排序后,截止到当前行,最后一个值
用于组内排序后,取第一个或最后一个值
SUM/AVG/MIN/MAX(col) over 
(partition_clause  [ order_by_clause [rows between xxx and xxx] ])
分组内求和/平均/最小/最大
若有order by而无window子句则相当于(分组内截止到当前行,且显示出的结果是分组内最后一种排序的)order by col rows between unbounded preceding and current row
xxx(rows between子句即window子句):
3 preceding 往前3行
2 following 往后2行
current row 当前行
unbounded preceding/following 起点/终点
用于组内求值
CUME_DIST/PERCENT_RANK() over 
([partition_clause]  order_by_clause)
CUME_DIST 小于等于当前值的行数/分组内总行数
PERCENT_RANK 分组内当前行的RANK值-1/分组内总行数-1
用于序列分析
group by col1,col2 GROUPING SETS(col1,col2,(col1,col2)) order by GROUPING__ID
根据不同的维度组合进行聚合,等价于将不同维度的group by结合集进行union all
GROUPING__ID 表示结果属于哪一个group by结合集
用于上卷和下钻维度的指标统计
group by col1,col2 with CUBE order by GROUPING__ID
根据GROUP BY的维度的所有组合进行聚合
(左例相当于不分组、对col1分组、对col2分组、对col1、col2分组 union all)
group by col1,col2 with ROLLUP order by GROUPING__ID
CUBE的子集,以最左侧维度为主,从该维度进行层级聚合。
首先是总体聚合、然后是按col1聚合、最后是按col1、col2聚合
3、合并记录函数(行列转换)
(1)行转列
  • 多行转多列
col1 col2 col3 a c 1 a d 2 a e 3 b c 4 b d 5 b e 6 转换成 col1 c d e a 1 2 3 b 4 5 6
此时需要使用到max(case … when … then … else 0 end),仅限于转化的字段为数值类型,且为正值的情况
select col1, max(case col2 when 'c' then col3 else 0 end) as c, max(case col2 when 'd' then col3 else 0 end) as d, max(case col2 when 'e' then col3 else 0 end) as e from row2col group by col1;
  • 多行转单列
col1 col2 col3 a b 1 a b 2 a b 3 c d 4 c d 5 c d 6 转换成 col1 col2 col3 a b 1,2,3 c d 4,5,6
a)cocat_ws(参数1,参数2),用于进行字符的拼接
必须要与group by合用,col必须是string或array,可以用cast(col as string)转换类型。col可以是非group by字段。oncat_ws(',', collect_list(col3))在impala里得用group_concat(),可以在group_concat()第二个参数指定分隔符,默认是逗号
参数1—指定分隔符
参数2—拼接的内容
b)collect_set(),它的主要作用是将某字段的值进行去重汇总,产生array类型字段
c) collect_list(), 不去重汇总
select col1, col2, concat_ws(',', collect_set(col3)) as col3 from row2col group by col1, col2;
(2)列转行
  • 多列转多行
col1 c d e a 1 2 3 b 4 5 6 转换成 col1 col2 col3 a c 1 a d 2 a e 3 b c 4 b d 5 b e 6
这里需要使用union进行拼接
select col1, 'c' as col2, c as col3 from col2row UNION select col1, 'd' as col2, d as col3 from col2row UNION select col1, 'e' as col2, e as col3 from col2row order by col1, col2;
  • 单列转多行
col1 col2 col3 a b 1,2,3 c d 4,5,6 转换成 col1 col2 col3 a b 1 a b 2 a b 3 c d 4 c d 5 c d 6
需要使用UDTF(表生成函数)explode(),该函数接受array类型的参数,其作用恰好与collect_set相反,实现将array类型数据行转列。explode配合lateral view实现将某列数据拆分成多行
select col1, col2, lv.col3 as col3 from col2row lateral view explode(split(col3, ',')) lv as col3;
4、字符串函数
nvl(col,val)
若col为空,则为val,否则为col
 
nvl2(col,val1, val2)
若col为空,则为val1,否则为val2
 
nullif(col1,col2)
若col1与col2相等,则返回空,否则返回col1
 
coalesce(...)
返回第一个非空值。可以包含任意多个参数,但类型必须相同,或可隐式转换为同类型
 
regexp_replace(str,oldstr,newstr)
   
split(str,regexp)
根据regexp分割字符串,返回一个数组。当regexp是特殊字符时,要在前面加\\,当split在""中时,\\要改为\\\\
split('192.168.0.1','\\.') hive -e "....  split('192.168.0.1','\\\\.') ... "
5、判断函数
if(boolean testCondition, T valueTrue, T valueFalseOrNull)
CASE a WHEN b THEN c [WHEN d THEN e]... [ELSE f] END
6、数字函数
ceil()
往上取整
floor()
往下取整
pmod(int a,int b)
pmod(double a,double b)
a的绝对值除以b的余数
7、json解析函数
get_json_object(string json_string, string path)
第一个参数填写json对象变量,第二个参数使用$表示json变量标识,然后用 . 读取对象,[] 读取数组;如果输入的json字符串无效,返回NULL
单层值 get_json_object(data, '$.owner')
多层值 get_json_object(data, '$.store.bicycle.price')
数组值 get_json_object(data, '$.store.fruit[0]')
十七、语句顺序
  • FROM
  • join
  • WHERE
  • GROUP BY
  • HAVING
  • SELECT  
  • OVER
  • DISTINCE
  • TOP
  • ORDER BY
十八、实现exist/in以及not exists/not in子句
exist/in、not exists/not in在hive中不支持,需要改写:
1、in:
SELECT a.key, a.value FROM a WHERE a.key in (SELECT b.key FROM B);
改成:
SELECT a.key, a.value FROM a LEFT OUTER JOIN b ON (a.key = b.key) WHERE b.key <> NULL;
2、not exists:
select a, b from table1 t1 where not exists (select 1 from table2 t where t1.a = t2.a and t1.b = t2.b)
改成:
select t1.a, t2.b from table1 t1 left join table2 t2 on (t1.a = t2.a and t1.b = t2.b) where t2.a is null
十九、锁
1、解锁表
unlock table t1;
posted @ 2025-07-01 20:19  码以致用  阅读(44)  评论(0)    收藏  举报