Hive SQL执行流程一条HQL进来第一步先通过SQL Parser把SQL字符串转成抽象语法树同时做语义分析然后语义分析器把抽象语法树编译成查询块第二步结合MeteStore里的元数据校验表存不存在字段存不存在第三步生成逻辑执行计划然后优化器按规则做一轮重写比如把过滤条件下推、把用不到的列裁掉、把常量表达式先算出来第四步转成物理执行计划拆成一个个MapReduce任务决定用几个Map几个Reduce这时候基于代价的优化器会算一笔账从几种Join方案里挑代价最小的。第五步执行生成底层代码提交到yarn上跑算完把结果返回Hive自定义函数流程有什么作用第一步写Java类继承GenericUDF重写initialize、evaluate、getDisplayString 三个方法第二步打成Jar包传到HDFS第三步注册 CREATE FUNCTION scott.HELLO_UDF AS ‘com.yjxxt.hive.udf.HelloUDF’ USING JAR ‘hdfs:///bd/hive-demo-1.0-SNAPSHOT.jar’默认注册到default库之后SQL里自定义函数就可以当系统函数直接用Hive分区和分桶分区是按字段值在表目录下再开一层子目录目录名就是 分区键键值逻辑上分区表和普通表没区别物理上数据按分区键值分目录存查询带上where dt ‘2026-09-02’就只扫这一个目录分区裁剪避免全表扫描分区分静态和动态还分单分区和多分区。分桶是把数据按hash字段% 桶数拆成固定几个文件好处有三个数据分布更细更均匀方便抽样提升JOIN效率Hive和传统数据库的区别Hive 和传统数据库最本质的区别是面向的场景不同。MySQL 是OLTP联机事务处理管的是前台业务一笔一笔的存取要毫秒级响应、要事务、要能随时修改删除一行数据数据量一般是 GB 级。Hive 是OLAP联机分析处理管的是海量历史数据的批量计算一次查询扫 TB 级数据跑几十秒到几分钟都很正常不适合高并发也没有行级更新。具体差在几个地方。存储上Hive 的数据在 HDFS 上分散在整个集群各节点的磁盘里传统数据库的数据文件就在本机块设备的本地文件系统上。数据更新上Hive 早期根本不支持修改删除数据是加载的时候就定好的0.14 之后才支持事务但前提很苛刻——ORC 格式加分桶再加 transactionaltrue。执行方式上Hive 是把 SQL 翻译成 MapReduce 或 Spark 任务丢到 YARN 上跑数据库用自己的执行引擎数据规模小的时候延迟很低。扩展性上Hive 跟 Hadoop 一样是线性扩展加机器就行数据库受 ACID 限制往上扩展收益有限。Hive物化视图和视图的区别普通视图是虚拟表只存SQL定义不存数据每次查都重新把创建它的SELECT执行一遍创建时结构会冻结底层表删了改了视图就失效。物化视图是把查询结果真正落一份数据的数据库对象专门预计算表连接、聚合这类耗时操作再查直接读结果。Hive内部表和外部表内部表 Hive既管元数据也管数据外部表Hive只管元数据表只是个指向外部目录的引用Hive导出数据有几种方式INSERT OVERWRITE DIRECTORY ‘/PATH’ SELECT … 导到HDFS目录INSERT OVERWRITE TABLE 表名 SELECT …导到另一张Hive表hdfs dfs -get / hdfs dfs -cp 把HDFS文件拉回本地或拷到别的目录EXPORT TABLE t_person TO ‘/bd/export/person’ 元数据加数据一起导出动态分区和静态分区两者的区别,本质是分区值什么时候确定、由谁确定。静态分区:分区值在 SQL 里写死,编译期就定了。比如 INSERT OVERWRITE TABLE t PARTITION(dt‘2026-09-07’) SELECT …,所有数据都进这一个目录。动态分区:分区值不写死,只写列名,比如 PARTITION(grade, clazz);Hive 执行时从 SELECT 结果集的最后几列取值,按值自动建目录——不同 grade、clazz 的数据自动落到各自目录。一句话:静态是手动指定,动态是自动分流。sort by / order by / distribute by / cluster bysort by 局部排序每个Reducer内部有序全局不一定有序会视情况起多个Reducer适合大数据集order by 全局排序最终结果整体有序但底层所有数据进一个Reducer做排序数据量大就成瓶颈大数据集效率非常低。distribute by 分区排序只管分发不管排序按指定字段做Hash散列控制某行去哪个Reducer目的是让相同Key进同一个Reducer。cluster by组合排序当distribute by 和 sort by 字段相同时组合排序等价于两者叠加又分又排相当于一个语法糖少写一点代码但是他只能升序。行式文件和列式文件行式存储一行接一行存一行数据在介质里连续存放取一整行很快新增和更新数据也方便适合事务处理但分析查询只查几列时会把整行都读出来不参与计算的列也照样IO而且一行里各列类型不一压缩比上不去。列式存储按列存同一列的值连续存放特征是扫很多行只查几列因为只读参与计算的列所以IO大幅降低且cpu缓存命中率也高并且同一个列类型也相同压缩比高的多存储和带宽都可以省还能选择最合适的压缩算法。常见SQL优化按优先级过一遍先用where把数据量压下去能带分区条件就带走分区裁剪。不要select *只取需要的列配合列裁剪投影下推省IO大表JOIN小表用Map Join小表广播进内存建HashTable避免大Shuffleleft join 左表必须为大表别写出笛卡尔积减少Shuffle聚合和join前先做局部聚合开hive.map.aggr走Map端预聚合countdistinct改写成先groupby再count因为它默认只用一个Reducer容易数据倾斜orderby改sortby limit做top-N数据倾斜原因读了大文件最常见为GZip压缩的大文件因为它不可分割只有一个Map读换成BZip2/LZO支持切分的去解决单表聚合时部分Key数据量特别大且大Key分散在很多切片里Shuffle后全压一个Reducer两表 JOIN 都含大量相同的倾斜 Key**热点记录全落同一个 Reducer分组列有大量 NULL、空字符串**——空值在 Hash 分区里算同一个 Key天然往一个 Reduce 挤聚合操作无法消减中间结果**比如COLLECT_LIST要收集全量数据大量数据必须过 Shuffle。追问怎么解决——空值问题成本最低INNER JOIN Hive 会自动过滤 NULL看 EXPLAIN 有predicate: deptno is not nullLEFT JOIN 不会那就先WHERE key IS NOT NULL过滤再 JOIN业务要保留 NULL 就给它拼随机前缀打散NVL(deptno, CONCAT(NULL_, CAST(RAND()*100 AS INT)))或者拆成两段 SQL 分别处理再 UNION ALL。聚合倾斜用两阶段加盐先CONCAT(RAND()*10, _, deptno)加盐做局部聚合再去盐全局聚合。JOIN 倾斜用Skew Joinhive.optimize.skewjointrue超过hive.skewjoin.key默认 100000 的 Key 单独拆出来走 MapJoin其余走 Common Join最后合并或者手动把倾斜 Key 的表拆成 Skew/Normal 两份分别处理再 UNION ALL。GROUP BY 倾斜可以开hive.groupby.skewindata拆两个 Job 做负载均衡。Hive优化Hive 优化分为四个维度建表存储、SQL 逻辑、引擎参数、以及数据倾斜。万变不离其宗核心心法就六个字少读、少传、少算。第一建表与存储优化少读。首选列式存储 ORC 或 Parquet配合合适的压缩算法如中间结果用 Snappy极致存储用 Zstd。同时结合业务做分区按日期和分桶查询时利用分区裁剪和列裁剪把不需要读的文件直接跳过。第二SQL 与执行计划优化少算/少传。写 SQL 时善用 RBO谓词下推、常量折叠和 CBO基于代价优化 Join 顺序小表先 Join。能用 GROUP BY 代替 COUNT(DISTINCT)全局排序 ORDER BY 必须加 LIMIT配合严格模式防呆。另外开启 Map 端预聚合Combiner减少 Shuffle 数据量。第三针对 Join 场景的专项优化。优先级从低到高大表 Join 大表用 Common Join走 Shuffle 最慢。小表 Join 大表用 Map Join小表广播进内存无 Shuffle。两表分桶且桶数成倍数用 Bucket Map Join。分桶且桶内排序用 SMB Join双游标归并内存极小速度极快。第四数据倾斜与参数调优兜底与防呆。如果出现大 Key 导致单节点 OOM首选过滤空值或手动加盐打散复杂场景直接开 Skew Join 自动拆解。参数层面开启向量化执行一次算1024行榨干 CPU开启 Shuffle 压缩Snappy合并小文件小任务开启本地模式最后用推测执行给慢节点兜底。追问 1Map Join 既然这么好为什么不全用 Map Join答Map Join 必须要求小表能放进每个 MapTask 的内存默认 25MB可调。如果小表过大广播会导致网络带宽打满且每个节点内存 OOM。所以只适合“大表 Join 极小表”。追问 2开了向量化为什么查询还是慢答向量化依赖列式存储ORC/Parquet。如果底层是 TextFile 这种行式存储或者查询里全是不支持向量化的复杂 UDF开了也没用。另外还要看 CPU 核数和内存是否足够。追问 3SMB Join 为什么比 Map Join 还快答Map Join 是把小表全量塞进内存。而 SMB Join 是两张表都分桶且排序它的 MapTask 只要取出对应的“同一个桶”做双指针归并内存占用极小速度快而且不怕两边数据量都很大。
阅读完成 · 觉得有帮助?