零基础起步:把第一条 HiveQL 跑通
这一页假设你什么都没做过。跟着 6 个关卡往下走,每一步都告诉你敲什么、屏幕上应该出现什么、出错了先查哪一条。全程约 40 分钟。
走完这 6 关,你就能
- 知道自己的 Hive 装在哪、怎么连上去
- 能独立建一个库、建一张表、把数据放进去
- 能用 SELECT 把数据查出来,并看懂返回结果
- 遇到常见报错能自己定位原因
关卡目录
第 0 关 · 先确认环境是好的(5 分钟)
前提:已经装好 Hadoop + MySQL + Hive(单元2 / 第4-5周实训做过这件事)
1看 Hadoop 是否在运行
🎯 在虚拟机上打开终端(或用 Xshell 连上去),输入下面这行。
jps10885 NodeManager 10327 DataNode 10522 SecondaryNameNode 10746 ResourceManager 10171 NameNode 11247 Jps
能看到 NameNode、DataNode、ResourceManager、NodeManager 就算正常。
只看到 Jps 一行
→ Hadoop 没启动。依次执行start-dfs.sh、start-yarn.sh,再jps确认。命令找不到
→ 环境变量没配好。执行source ~/.bashrc,或用绝对路径$HADOOP_HOME/sbin/start-dfs.sh。
2看元数据库能不能连上
🎯 Hive 的表结构信息都放在 MySQL 里,连不上它 Hive 一定起不来。
mysql -uhive -phive123456 -e "use hive; show tables;"BUCKETING_COLS CDS COLUMNS_V2 DBS TBLS …(一长串 Hive 自动建的元数据表)
只要不报错、能看到一串表名就说明元数据库正常。
Access denied for user 'hive'
→ 账号或密码不对;确认第4周实训里创建的 hive 账号和授权是否执行过。Can't connect to local MySQL server
→ MySQL 没启动:systemctl start mysqld。表很少或没有
→ 元数据没初始化:在 Hive 安装目录执行schematool -initSchema -dbType mysql。
3看 Hive 装在哪、用哪个命令启动
🎯 确认 Hive 的安装目录和环境变量,后面要靠它启动。
echo $HIVE_HOME
ls $HIVE_HOME/bin | head/export/servers/hive-4.1.0 beeline hive ext hive-config.sh …
能打印出安装路径,并且 bin 目录里能看到 beeline 就够了。
输出空行
→ HIVE_HOME 没配。编辑vi ~/.bashrc,加入export HIVE_HOME=/export/servers/hive-4.1.0和export PATH=$HIVE_HOME/bin:$PATH,再source ~/.bashrc。
4启动 HiveServer2 并确认端口
🎯 远程模式(多人用、后面配 DataGrip)必须启动它。
hiveserver2 &
sleep 5
netstat -nltp | grep 10000tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 12345/java
看到 LISTEN 就说明 10000 端口在监听,可以连了。
端口没监听
→ 看日志找原因:tail -100 $HIVE_HOME/logs/hive.log,常见是元数据库连不上。端口被占用
→ 改hive-site.xml里的hive.server2.thrift.port,或用kill -9 进程号结束旧进程。
第 1 关 · 连上 Hive 客户端(3 分钟)
前提:第 0 关全部通过
1方式一:Beeline 连 HiveServer2(推荐)
🎯 这是生产环境的标准做法,后面 DataGrip 连的也是这个地址。
beeline -u "jdbc:hive2://hadoop1:10000" -n hadoopConnected to: Apache Hive (version 4.1.0) Driver: Hive JDBC (version 4.1.0) Beeline version 4.1.0 by Apache Hive 0: jdbc:hive2://hadoop1:10000>
最后那行 0: jdbc:hive2://…> 就是提示符,说明你已经进到 Hive 里了,后面所有 SQL 都敲在这里。
Connection refused
→ HiveServer2 没起来,回到第 0 关第 4 步。User: hadoop is not allowed to impersonate
→ Hadoop 端代理配置缺失,按第5周实训配置hadoop.proxyuser.hadoop.hosts等相关参数。
2方式二:本地模式直接敲 hive(最省事)
🎯 元数据在本机 MySQL 时,直接用 hive 命令即可,不用起服务。
hivehive (default)>
提示符里括号内的 default 是当前所在的数据库,它会随 USE 语句变化。
卡住不动或报 Metastore 相关错误
→ 元数据库配置有问题,检查hive-site.xml里的javax.jdo.option.ConnectionURL。
3方式三:不进去,直接跑一句就退出
🎯 写脚本、做定时任务时最常用。
hive -e "show databases;"OK default Time taken: 0.856 seconds, Fetched: 1 row(s)
-e 后面跟 SQL;批量脚本用 -f 文件名.sql。
命令很长不好敲
→ 把 SQL 存成文件:vi t.sql写入语句,再hive -f t.sql。
4记住三个“退出/帮助”命令
🎯 新手最容易卡在"怎么出去"。
!quit -- 退出 Beeline
!help -- 看 Beeline 自己的命令
quit; -- 在 hive 命令行里退出(回到 Linux 命令行提示符)
以 ! 开头的是 Beeline 的命令,不是 SQL,结尾不用分号。
第 2 关 · 建库:把自己的"抽屉"建出来(4 分钟)
前提:已连上 Hive(第 1 关)
1① 先看现在有哪些库
🎯 养成"先看再做"的习惯,避免重复建、建错地方。
SHOW DATABASES;OK default Time taken: 0.234 seconds, Fetched: 1 row(s)
刚装好只有 default 一个库,它是默认库,正式项目别把表建在这里。
2② 写建库语句(逐段看懂)
🎯 把这条语句敲进去,注意分号是语句结束符,别漏。
CREATE DATABASE IF NOT EXISTS school
COMMENT '校园选课演示库'
LOCATION '/user/hive/warehouse/school.db';| 语句片段 | 含义 |
|---|---|
CREATE DATABASE | 建库的关键字,也可以写成 CREATE SCHEMA,两者等价 |
IF NOT EXISTS | 已经存在同名库时不报错直接跳过(脚本里建议都带上) |
COMMENT '…' | 给库加一句说明,方便别人看懂;单引号里的中文没问题 |
LOCATION '…' | 指定这个库在 HDFS 上的目录;不写就用默认仓库目录 |
OK Time taken: 0.512 seconds
返回 OK 就是建好了。Hive 的 DDL 通常只回 OK,不像 MySQL 那样回详细信息。
ParseException … cannot recognize input near
→ 十有八九是标点问题:分号写成中文分号、引号用了中文引号,或者少了一个括号。Permission denied: user=…, access=WRITE, inode="/user/hive/warehouse"
→ 仓库目录没有写权限:hdfs dfs -chmod -R 777 /user/hive/warehouse。
3③ 切进去 + 确认自己在哪
🎯 建完库必须 USE 进去,否则表还会建到 default 里。
USE school;
SELECT current_database();OK Time taken: 0.1 seconds _c0 school Time taken: 0.3 seconds
提示符里的 default 也会变成 hive (school)>,这就是"我当前在哪个库"的提示。
Database does not exist: school
→ 上一步没建成功,或者名字打错(Hive 库名区分大小写)。重跑第 ② 步。
4④ 到 HDFS 上亲眼看看这个库
🎯 把"库 = 目录"这件事看实了,后面分区、分桶就好理解了。
hdfs dfs -ls /user/hive/warehouse/drwxrwxrwt - hadoop supergroup 0 2025-07-01 10:12 /user/hive/warehouse/school.db
school.db 这个目录就是刚才建的库。库名后面固定加 .db。
目录不存在
→ 建库时 LOCATION 写了别的路径,去那个路径找;或执行DESCRIBE DATABASE EXTENDED school;查真实位置。
第 3 关 · 建表:六行语句拆开看(8 分钟)
前提:已 USE school(第 2 关)
1① 敲这条建表语句
🎯 先整条敲进去,看不懂没关系,下一步逐行解释。
CREATE TABLE IF NOT EXISTS student_info(
stu_id STRING COMMENT '学号',
stu_name STRING COMMENT '姓名',
birthday STRING COMMENT '出生日期',
sex STRING COMMENT '性别'
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE;OK Time taken: 0.421 seconds
建表只改元数据,瞬间完成,不产生任何数据文件。
ParseException line 1:33 cannot recognize input near '(' in …
→ 括号对不上。字段列表必须用一对圆括号包起来,字段之间用英文逗号。表已存在但结构不对
→ 先DROP TABLE student_info;再重建。
2② 六行分别是什么意思
🎯 照着下面这张表逐行对照,理解了以后所有建表语句都是这套结构。
| 语句片段 | 含义 |
|---|---|
第 1 行 CREATE TABLE IF NOT EXISTS student_info( | 建一张名叫 student_info 的表;( ) 里写字段清单 |
第 2–5 行 字段名 类型 COMMENT '说明' | 每个字段一行:名字、类型(STRING/INT 等)、注释。字段之间用逗号,最后一个字段后面不要加逗号 |
第 6 行 ) | 收尾的右括号,表示字段写完了 |
第 7 行 ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' | 告诉 Hive:数据文件里每个字段用英文逗号分隔。这一行必须和你数据文件的真实分隔符一致 |
第 8 行 STORED AS TEXTFILE | 数据文件存成普通文本。练习用 TEXTFILE 最直观(能用 cat 直接看);正式仓库常换成 ORC(列存、更快更省) |
结尾分号 ; | 语句结束。Hive 里可以一条语句写多行,一直到分号才算结束 |
3③ 检查结构建对没有
🎯 建完一定要看一眼结构,这是最省事的自检。
DESC student_info;col_name data_type comment stu_id string 学号 stu_name string 姓名 birthday string 出生日期 sex string 性别
字段名、类型、注释三列都对上就说明建好了。想看更全的信息用 DESC FORMATTED student_info;。
Table not found: student_info
→ 表没建成,或者你不在 school 库里。执行USE school;再SHOW TABLES;确认。中文注释显示成乱码
→ 客户端字符集问题,不影响使用;换成 Beeline 或 DataGrip 一般就正常了。
4④ 到 HDFS 上看表长什么样
🎯 再确认一次"表 = 库目录下的一个子目录"。
hdfs dfs -ls /user/hive/warehouse/school.db/drwxr-xr-x - hadoop supergroup 0 … /user/hive/warehouse/school.db/student_info
目录是空的——因为还没放数据。下一步就来放。
表目录不存在
→ 表可能建到了 default 库:去 /user/hive/warehouse/student_info 找找。
第 4 关 · 把数据放进去(6 分钟)
前提:student_info 表已建好(第 3 关)
1① 在 Linux 上准备一个数据文件
🎯 Hive 的数据本来就是文本文件。注意:字段顺序要和建表时一致,用英文逗号分隔。
mkdir -p /home/hadoop/data
vi /home/hadoop/data/student_info.txt
# 文件内容(四行,每行四个字段):
001,彭于晏,1995-05-16,男
002,胡歌,1994-03-20,男
003,周杰伦,1995-04-30,男
004,刘德华,1998-08-28,男(vi 里按 i 进入编辑,粘贴内容,按 Esc 再输入 :wq 保存退出)
用 cat /home/hadoop/data/student_info.txt 确认文件内容确实是四行四列。
中文变乱码
→ 文件存成 UTF-8 即可;vi 里可用:set encoding=utf-8。不小心把文件存成了 .txt.txt
→ls -l看一眼真实文件名,LOAD 时名字要完全一致。
2② 加载数据(LOAD DATA)
🎯 回到 Hive 客户端(第 1 关那个提示符),执行下面这句。
LOAD DATA LOCAL INPATH '/home/hadoop/data/student_info.txt'
INTO TABLE student_info;| 语句片段 | 含义 |
|---|---|
LOAD DATA | 加载数据的固定开头 |
LOCAL | 从客户端本机读文件(复制过去)。不写 LOCAL 就从 HDFS 读(移动过去) |
INPATH '…' | 文件所在路径,用单引号包起来,必须是完整路径 |
INTO TABLE student_info | 装进哪张表;写成 OVERWRITE INTO 就是先清空再装 |
Loading data to table school.student_info OK Time taken: 0.912 seconds
Hive 只是把文件搬到表的目录里,不做解析,所以再大的文件也很快。
Invalid path: /home/hadoop/data/student_info.txt
→ 路径写错或文件不存在。ls -l 路径确认一下。SemanticException … Table not found
→ 不在 school 库里。先USE school;。
3③ 查三行,确认数据真的进来了
🎯 加载完必须验证。LIMIT 只取前几行,速度快。
SELECT * FROM student_info LIMIT 3;stu_id stu_name birthday sex 001 彭于晏 1995-05-16 男 002 胡歌 1994-03-20 男 003 周杰伦 1995-04-30 男
看到数据就成功了。SELECT * 表示"所有字段",LIMIT 3 表示只看 3 行。
查出来全是 NULL
→ 分隔符和建表时不一致:文件里是逗号,但建表写成了 \t,改成逗号重建表。一行都没有(0 行)
→ 数据装到别的表/库里了。在 HDFS 上确认:hdfs dfs -ls /user/hive/warehouse/school.db/student_info。字段串行错位
→ 文件里字段顺序和建表顺序不一致,按建表顺序重排数据文件。
4④ 再学一招:直接 INSERT 两条
🎯 少量补录、做测试时很方便。
INSERT INTO student_info VALUES ('005','唐国强','1993-09-10','男');
SELECT count(*) FROM student_info;OK Time taken: 12.5 seconds _c0 5 Time taken: 8.3 seconds
注意耗时:INSERT 会起一个计算作业,比 LOAD 慢得多。所以大批量数据一定要用 LOAD。
报错说需要事务表
→ Hive 4 里 INSERT VALUES 到普通表是可以的;若报 ACID 相关错误,说明表属性被改过,重建表即可。
第 5 关 · 把数据查出来(8 分钟)
前提:表里有数据(第 4 关)
1① 查全部 / 查指定列
🎯 先学会控制"看哪些列",别动不动就 SELECT *。
SELECT * FROM student_info;
SELECT stu_name, sex FROM student_info;4 行(或 5 行,取决于上一步是否 INSERT 过) stu_name sex 彭于晏 男 …
列存格式下只读用到的列能省大量 I/O,所以正式查询要列清单。
2② 加条件:WHERE
🎯 筛出你要的行。字符串要用单引号。
SELECT stu_name, birthday FROM student_info
WHERE sex = '男' AND birthday > '1995-01-01';stu_name birthday 彭于晏 1995-05-16 周杰伦 1995-04-30 刘德华 1998-08-28
AND 表示"并且";OR 表示"或者";日期字符串可以直接比较大小。
报错 cannot recognize input near '男'
→ 引号用了中文引号,或者字符串没加引号。改成英文单引号。
3③ 排序 + 限量:ORDER BY … LIMIT
🎯 取"最……的几个"是最高频的需求。
SELECT stu_name, birthday FROM student_info
ORDER BY birthday DESC LIMIT 2;stu_name birthday 刘德华 1998-08-28 彭于晏 1995-05-16
DESC 从大到小(新的在前),ASC 从小到大。LIMIT 2 只取前两行。
4④ 分组统计:GROUP BY
🎯 把明细变成指标,这是数仓的核心动作。
SELECT sex, count(*) AS 人数
FROM student_info
GROUP BY sex;sex 人数 男 4 女 0(如果还没插女生数据)
count(*) 数行数,AS 人数 给结果列起个中文别名。SELECT 里只能出现"分组列 + 聚合函数"。
报错 Expression not in GROUP BY key
→ SELECT 里出现了没参与分组的普通列。要么加进 GROUP BY,要么用聚合函数包起来。
5⑤ 一次练完:把这四步连起来
🎯 综合起来写一条,感受一下真实查询的样子。
SELECT sex,
count(*) AS 人数,
max(birthday) AS 最小的生日
FROM student_info
WHERE stu_id LIKE '00%' -- 只统计 00 开头的学号
GROUP BY sex
ORDER BY 人数 DESC;sex 人数 最小的生日 男 4 1998-08-28
执行顺序是:FROM → WHERE → GROUP BY → SELECT → ORDER BY。所以 WHERE 里不能写聚合函数,HAVING 才可以。
第 6 关 · 改与删:把东西收拾干净(4 分钟)
前提:前面几关都做过
1① 加字段、改字段名
🎯 表结构不是一次定死的,随时可以调整。
ALTER TABLE student_info ADD COLUMNS (class_id STRING COMMENT '班级');
ALTER TABLE student_info CHANGE sex gender STRING COMMENT '性别';
DESC student_info;col_name data_type comment stu_id string 学号 … class_id string 班级
ADD COLUMNS 只能加在最后(分区列之前);CHANGE 是"旧名 新名 新类型"的顺序。已有数据不会自动转换。
加字段后查到的是 NULL
→ 老数据文件里没有这一列,属于正常现象。
2② 清空数据但保留表
🎯 重跑实验时常用。
TRUNCATE TABLE student_info;
SELECT count(*) FROM student_info;OK _c0 0
表结构还在,数据文件被删掉了。外部表不能 TRUNCATE。
报错说外部表不能清空
→ 用INSERT OVERWRITE写一个空结果集来变相清空,或者直接删 HDFS 上的文件。
3③ 删表:内部表 vs 外部表(重要)
🎯 先看差别,再动手删,避免误删生产数据。
-- 内部表:删表 = 元数据 + 数据一起删
DROP TABLE IF EXISTS student_info;
-- 外部表:只删元数据,HDFS 上的文件保留
CREATE EXTERNAL TABLE ext_demo(id STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/user/hadoop/demo';
DROP TABLE ext_demo;
-- 此时 /user/hadoop/demo 里的文件还在OK Time taken: 0.3 seconds(两种表都回 OK,但后果不同)
记牢一句话:外部表的数据不归 Hive 管,别人给的数据一律用外部表接。
DROP DATABASE 报库非空
→ 加 CASCADE:DROP DATABASE school CASCADE;(会连表一起删,慎用)。
4④ 收尾:把练习环境清掉
🎯 保持环境干净,下次实验从零开始不会互相干扰。
DROP TABLE IF EXISTS student_info;
DROP DATABASE IF EXISTS school CASCADE;OK Time taken: 0.4 seconds
到此为止,你已经完整走了一遍:连客户端 → 建库 → 建表 → 装数据 → 查询 → 清理。接下来去单元3、单元5 做更完整的实例。
常见报错速查 按报错里的关键字搜索本页(Ctrl+F)
| 报错关键字 | 原因 | 怎么解决 |
|---|---|---|
FAILED: SemanticException [Error 10072]: Database does not exist: school | 库不存在,或没切换过去 | 先 CREATE DATABASE school; 再 USE school; |
FAILED: SemanticException [Error 10001]: Line 1:14 Table not found 'student_info' | 表名打错,或表建在别的库里 | SHOW TABLES; 看当前库有哪些表,必要时写全名 school.student_info |
FAILED: ParseException line 1:0 cannot recognize input near … | SQL 语法错误:中文标点、括号不配对、少分号 | 把标点全部换成英文,检查括号与引号是否成对 |
java.net.ConnectException: Call From … to hadoop1:9000 failed on connection exception | HDFS 没启动 | start-dfs.sh 后用 jps 确认 NameNode 在 |
MetaException(message:Got exception: java.net.ConnectException … 3306) | MySQL 元数据库连不上 | 检查 MySQL 是否启动、账号密码与 hive-site.xml 中的 JDBC 配置 |
Error: Could not open client transport with JDBC Uri … Connection refused | HiveServer2 未启动或端口不对 | 执行 hiveserver2 &,用 netstat -nltp | grep 10000 确认端口 |
Permission denied: user=hadoop, access=WRITE, inode="/user/hive/warehouse" | 仓库目录权限不足 | hdfs dfs -chmod -R 777 /user/hive/warehouse |
Invalid path ''/home/hadoop/data/xx.txt'': No files matching path | LOAD 的文件路径不存在 | ls -l 确认路径与文件名,注意 LOCAL 与 HDFS 的区别 |
FAILED: SemanticException [Error 10096]: Dynamic partition strict mode requires at least one static partition column | 动态分区没开或模式不对 | SET hive.exec.dynamic.partition=true; 与 SET hive.exec.dynamic.partition.mode=nonstrict; |
FAILED: SemanticException Table is not partitioned but partition spec exists | 往没分区的表里写了 PARTITION | 要么去掉 PARTITION 子句,要么用 PARTITIONED BY 重建分区表 |
FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask | 作业执行失败,多半是内存不足或数据问题 | 看 YARN 日志;调大内存 SET mapreduce.map.memory.mb=2048; |
Container killed by YARN for exceeding memory limits | 单个容器内存超限 | 调大容器内存,或减小单次处理的数据量(加分区过滤) |
FAILED: SemanticException [Error 10249]: Line 1:23 Unsupported SubQuery Expression | 在不支持的位置使用了子查询 | 把子查询改写成 JOIN 或 WITH 形式 |
HiveException: Table is not ACID / Table must be bucketed and stored as ORC | UPDATE/DELETE 需要事务表 | 建表时加 CLUSTERED BY … INTO n BUCKETS STORED AS ORC TBLPROPERTIES('transactional'='true') |
FAILED: RuntimeException … Expected 3 buckets but found 4 | 分桶表桶数与设置不一致 | 保证 hive.enforce.bucketing=true,并按建表桶数写入 |
SemanticException: Line 1:23 Expression not in GROUP BY key | SELECT 里有没参与分组的列 | 把该列加进 GROUP BY,或用聚合函数(如 max())包起来 |
FAILED: Execution Error … Error while compiling statement: … Unknown function | 函数名写错,或自定义函数没注册 | SHOW FUNCTIONS '关键字.*'; 查函数名;自定义函数先 ADD JAR + CREATE TEMPORARY FUNCTION |
Killed / OutOfMemoryError: Java heap space | 内存不足 | 调小数据量、开启中间结果压缩,或给客户端加内存 export HADOOP_CLIENT_OPTS="-Xmx2048m" |
完成自检清单
- ☐ 能说出 Hive 依赖的三样东西(HDFS、YARN/Tez、元数据库)
- ☐ 能用 Beeline / hive 两种方式连上并退出
- ☐ 能独立写出 CREATE DATABASE 与 CREATE TABLE 语句
- ☐ 知道 LOAD 与 INSERT 的区别和各自适用场景
- ☐ 能写带 WHERE / ORDER BY / LIMIT / GROUP BY 的查询
- ☐ 能说出内部表与外部表在删除时的差别
- ☐ 遇到报错知道先看哪几个地方(库名、表名、路径、权限、服务是否启动)
全部打勾,就可以放心去单元3 做完整的建库建表实例了。