生而为人

程序员的自我修养

0%

待整理

[toc]

离线数据仓库

数据仓库项目高频常见问题 + 原因 + 解决方案(面试直接背)

Ai prompt: 数据仓库项目中经常遇到的问题有哪些

我按离线数仓、实时数仓、SQL 开发、数据质量、调度运维、业务建模六大类整理,全是工作真实踩坑,面试问「项目遇到什么困难」直接套。

一、离线数仓常见问题

1. 数据倾斜(最常遇到)

现象:任务跑很久、个别 Reduce 卡死、数据量小却耗时极高。

原因:空值过多、热点 Key(热门商家 / 热门商品)、哈希分区不均。

解决方案

  • 空值加随机后缀打散
  • 热点 Key 单独过滤单独 join
  • 倾斜 key 加盐随机打散再聚合
  • 小表走 MapJoin 广播

2. 小文件过多

现象:HDFS 文件碎片多、NameNode 压力大、查询慢、任务启动慢。

原因:动态分区、频繁 insert overwrite、流式写入、分区粒度太细。

解决:定时合并小文件、设置输出 分片数、合理生命周期、控制动态分区数量。

3. 分区异常、分区遗漏

现象:某一天数据没产出、查不到分区、分区时间错乱。

原因:调度超时、任务失败未重跑、手动删分区、时区问题。

解决:增加分区校验脚本、失败自动重试、定时巡检分区完整性。

4. 表膨胀、历史数据冗余

现象:表越来越大、存储成本高、查询变慢。

原因:不做生命周期、拉链表无过期清理、每日全量覆盖。

解决:配置分区生命周期、冷数据归档、定期清理无用快照。

二、SQL 开发常见问题

1. 大表 Join 性能极差

现象:多张大表关联,任务跑几小时甚至挂掉。

原因:未过滤直接关联、笛卡尔积、分区没裁剪、字段冗余太多。

解决:先过滤再 Join、分区裁剪、只查必要字段、拆分成多段 SQL。

2. 重复数据、明细重复

现象:日活偏高、指标重复统计。

原因:业务重复上报、日志重复、全量同步未去重。

解决:row_number 分组去重、唯一键约束、业务主键判重。

3. 开窗函数滥用

现象:分区太大导致内存溢出、任务 OOM。

原因:partition by 字段粒度太粗、不做前置过滤。

解决:先过滤再开窗、缩小分区范围、拆分复杂逻辑。

4. 数据口径不一致

现象:同样指标报表、大屏、业务库数值对不上。

原因:各开发自己写逻辑、没有统一指标字典、时间范围不同。

解决:统一 ADS 层口径、建立指标字典、统一时间粒度和过滤条件。

1. 数据乱序、时间漂移

现象:实时指标忽高忽低、当天数据不准。

原因:设备时间不准、网络延迟、日志乱序到达。

解决:事件时间 + 水位线、设置乱序容忍、迟到数据侧输出补批。

2. 消息积压、Kafka 堆积

现象:消费延迟越来越大、实时变成准实时。

原因:消费并行度不够、算子逻辑太重、下游写入慢。

解决:提升并行度、拆分复杂算子、下游批量写入、异步 Sink。

3. 重复消费、数据重复写入

现象:实时指标翻倍、明细重复。

原因:Checkpoint 失败重启、offset 重复消费、Sink 无幂等。

解决:开启 Exactly-Once、幂等写入、按业务主键去重、Doris Unique 模型。

4. 维表关联延迟、维度不准

现象:用户属性、商品类目变更后实时没更新。

原因:维表缓存太久、全量加载不及时。

解决:Redis 维表 TTL 过期、定时全量刷新、CDC 实时同步维表。

5. Doris/StarRocks 写入瓶颈

现象:导入失败、版本冲突、写入超时。

原因:写入频率太高、分批太小、键冲突。

解决:批量攒批写入、调整分批大小、使用 Unique 去重。

四、数据质量类问题

  1. 脏数据多:空值、异常值、乱码、格式不统一
  2. 数据准确性差:指标对不上、统计逻辑漏洞
  3. 完整性不足:缺分区、缺字段、链路断流
  4. 及时性不够:离线报表出数晚、实时大屏延迟高

通用解决:DWD 层统一清洗、数据质量监控告警、定时校验环比波动。

五、调度与运维问题

  1. 任务依赖混乱:循环依赖、依赖链太长、一个失败全链路挂

  2. 调度超时:资源不足、排队严重、高峰任务扎堆

  3. 任务失败率高

    :SQL 不健壮、集群波动、资源抢占

    解决

    :梳理依赖拓扑、错峰调度、任务容错重试、资源队列隔离。

六、业务建模常见问题

  1. 分层不规范:ODS 做清洗、DWD 做聚合,职责混乱
  2. 宽表设计不合理:字段冗余过多、粒度不统一
  3. 缓慢变化维度处理不当:维度变更无历史快照、无法回溯
  4. 主题域划分混乱:表归属不清、复用性差

面试一句话总结(直接背诵)

数仓项目日常主要遇到:数据倾斜、小文件泛滥、分区异常、大表 Join 性能差、数据重复、口径不一致、实时乱序积压、维度不准、调度依赖混乱、脏数据与数据质量波动;一般通过SQL 优化、拆分逻辑、加盐打散、分区生命周期、水位线乱序处理、统一建模与指标口径、监控巡检来解决。

数仓建表 & 元数据 面试高频必问题库(全覆盖,直接背)

AI prompt: 建表元数据可能被问到的问题有哪些

建表语法、表类型、分区分桶、存储格式、元数据概念、元数据管理、元数据血缘、踩坑问题分类,全是面试原题。

一、基础建表必问

  1. Hive 建表语法包含哪些核心要素?
  2. 建表时 externalinternal 区别?生产为什么全用外部表?
  3. 建表 comment、字段注释有什么意义?元数据为什么必须加注释?
  4. 建表指定 row format delimited 作用是什么?
  5. 分隔符指定错误会有什么后果?怎么排查?
  6. 建表指定存储格式:ORC/Parquet/Text 怎么选?各自优缺点?
  7. 建表指定压缩格式:Snappy、Gzip 适用场景?
  8. 什么是临时表?临时表特点、生命周期、使用场景?
  9. 什么是视图 View?视图和物理表区别?视图占存储吗?
  10. 什么是物化视图?和普通视图区别、数仓用途?

二、分区 & 分桶 建表高频

  1. 什么是分区表?分区作用、原理?
  2. 静态分区、动态分区区别?建表怎么定义?
  3. 动态分区有哪些坑?生产注意什么参数?
  4. 分区字段为什么不能和业务字段重复?
  5. 什么是分桶表?分桶原理、适用场景?
  6. 分区和分桶区别?各自解决什么问题?
  7. 建表时分区分桶顺序怎么写?谁在前谁在后?
  8. 多级分区适用什么业务?有什么弊端?
  9. 分区过多会有什么问题?怎么治理?
  10. 分区漂移是什么?怎么产生、怎么避免?

三、表结构 & 粒度建模类

  1. 事实表、维度表建表设计有什么区别?
  2. 宽表建表原则?字段怎么取舍?
  3. 拉链表怎么建表?关键字段有哪些(start_dt、end_dt)?
  4. 流水表、快照表建表结构差异?适用场景?
  5. 增量表、全量表建表设计区别?
  6. 建表时字段类型怎么选型?string/int/bigint/double/decimal 区别?
  7. 金额为什么要用 decimal 不用 double?有什么坑?
  8. 数组、Map 类型什么时候用?炸裂函数配合什么表结构?
  9. 建表要不要默认值?空值怎么处理?
  10. 同主题多张表字段命名怎么统一?元数据规范怎么做?

四、元数据基础概念必问

  1. 什么是元数据?元数据包含哪些内容?

  2. 数仓中元数据分哪几类?

    • 业务元数据、技术元数据、管理元数据
  3. 技术元数据包含什么?

    表名、字段名、字段类型、注释、分区、存储路径、格式、建表时间、责任人

  4. 业务元数据包含什么?

    业务口径、指标含义、业务域、业务归属、业务负责人

  5. 管理元数据包含什么?

    任务调度、责任人、生命周期、权限、热度访问量

  6. 元数据的作用是什么?(面试高频)

  7. 为什么建表必须规范注释、规范命名?

  8. 元数据不规范会带来什么问题?

五、元数据管理平台相关(必问)

  1. 你们公司用什么元数据平台?(DataHub/Atlas/ 自研)
  2. 元数据采集原理是什么?
  3. Hive 元数据存在哪里?MySQL 元数据库存什么?
  4. Hive Metastore 架构?本地元数据 & 远程元数据区别?
  5. 元数据同步延迟怎么解决?
  6. 元数据可以自动采集哪些信息?表、字段、分区、任务、血缘?
  7. 怎么手动维护元数据?什么时候需要人工补元数据?

六、数据血缘 元数据核心高频

  1. 什么是数据血缘?字段级血缘和表级血缘区别?
  2. 血缘怎么自动生成?底层原理?
  3. 血缘断裂是什么原因?怎么修复?
  4. 改一张表字段,怎么通过元数据影响下游哪些报表?
  5. 下线一张表,怎么排查有没有业务在用?
  6. 元数据血缘在故障排查、口径对齐中怎么用?

七、权限 & 生命周期 元数据相关

  1. 表生命周期怎么在建表 / 元数据中配置?作用?
  2. 冷数据、热数据怎么通过元数据标识?
  3. 表权限、字段级权限怎么依赖元数据管控?
  4. 怎么通过元数据做资产盘点、无用表下线?
  5. 怎么基于元数据做数据治理、质量监控?

八、建表 & 元数据 工作踩坑面试题

  1. 建表字段类型选错,会有什么后果?
  2. 建表没加注释,后续带来什么麻烦?
  3. 元数据和 HDFS 实际数据不一致怎么排查?
  4. 删除元数据但没删 HDFS 数据会怎样?
  5. 重复建表、同名表冲突怎么处理?
  6. 分区元数据损坏、修复分区怎么做?
  7. 表改名后元数据、血缘会不会断?
  8. 跨引擎 Hive/Doris 元数据怎么统一管理?

九、面试官常追问一句话

  1. 你在建表时遵循哪些规范?
  2. 你怎么保证团队元数据规范、统一?
  3. 元数据在数仓项目里价值体现在哪?

数仓建表 + 元数据 面试极简一页纸背诵版(全是标准答案,直接背)

一、建表核心必背问答

1. Hive 建表核心要素

表名、字段名 + 类型 + 注释、分区字段、分桶规则、行格式分隔符、存储格式、压缩格式、表类型、存储路径、生命周期、责任人注释。

2. 内部表和外部表区别,生产为啥用外部表

内部表:删表连带删 HDFS 数据,元数据和数据强绑定;

外部表:删表只删元数据,HDFS 数据保留;

生产全用外部表,防止误删原始数据,方便数据回溯和跨任务复用。

3. 分区是什么、作用

按时间 / 维度切分目录,分区裁剪减少扫描数据、提升查询速度、方便按天管理数据。

4. 静态分区 vs 动态分区

静态:固定写死分区值,安全可控;

动态:根据数据自动生成分区,适合批量落地;

生产注意:开启动态分区参数,禁止全动态分区,避免产生大量小分区。

5. 分桶是什么、作用

按字段 Hash 打散到固定个数文件;优化Join、抽样、去重、关联查询,让相同 key 落在同一个桶。

6. 分区和分桶区别

分区是目录级别,粗粒度过滤;

分桶是文件级别,细粒度打散优化关联。

7. 常用存储格式选型

Text:原始文本,可读性高、无压缩、占用大;

ORC:列式存储、压缩率高、查询快、数仓首选

Parquet:跨引擎兼容好,Spark/Flink/Doris 通用。

8. 金额为啥用 decimal 不用 double

double 浮点有精度丢失,金额、汇率必须用 decimal 保证计算精准。

9. 视图和物化视图区别

普通视图:只存 SQL 逻辑,不存真实数据,查询实时计算;

物化视图:预计算落地物理数据,查询更快、复用预聚合结果

10. 拉链表建表核心字段

业务主键、开始时间 start_dt、结束时间 end_dt;用来保存维度历史快照,支持任意时间回溯。

二、元数据基础必背

1. 什么是元数据

描述数据的数据,用来记录表、字段、任务、业务口径的所有描述信息。

2. 元数据三大分类

  1. 技术元数据:表名、字段、类型、注释、分区、存储路径、格式、建表时间;
  2. 业务元数据:业务域、指标口径、业务含义、归属业务线;
  3. 管理元数据:责任人、生命周期、调度信息、权限、访问热度。

3. 元数据有什么作用

规范建表、统一字段口径、自动生成数据血缘、故障溯源、资产盘点、无用表下线、数据治理、权限管控。

4. 为什么建表必须加注释、规范命名

方便团队看懂表和字段含义;保证元数据完整、血缘准确、口径统一;后续维护、交接、新人上手不用猜逻辑。

三、元数据架构与采集

1. Hive 元数据存在哪

元数据服务 Metastore,元数据信息存在MySQL 元数据库,真实数据存在 HDFS。

2. 本地元数据 和 远程元数据

本地:仅当前客户端可用,适合单机测试;

远程:独立 Metastore 服务,团队共享、所有引擎统一访问,生产必用

3. 元数据采集原理

通过引擎元数据库、SQL 解析、日志解析,自动采集表、字段、分区、任务依赖,生成表级和字段级血缘。

四、数据血缘高频问答

1. 什么是数据血缘

记录表与表、字段与字段之间的上下游依赖关系,追踪数据从哪来、经过哪些加工、输出到哪。

2. 表级血缘 vs 字段级血缘

表级:只看整张表上下游;

字段级:精确到每个字段的来源、加工逻辑、下游引用,排查口径不一致必备。

3. 血缘断裂原因

SQL 写法不规范、临时表中转、视图嵌套、改字段不更新元数据、跨引擎任务无解析。

4. 血缘实际用途

改表前评估下游影响、故障快速定位链路、下线表排查是否有人在用、口径不一致溯源。

五、建表 & 元数据常见踩坑及解决

  1. 字段类型选错:精度丢失、关联不上;建表提前评估业务类型,金额用 decimal。
  2. 无注释:后续无人看懂、无法做血缘治理;强制建表必加表和字段注释。
  3. 元数据与 HDFS 数据不一致:手动删 HDFS 文件、元数据残留;定时修复分区、巡检元数据完整性。
  4. 分区过多、小文件泛滥;合理设置分区粒度、配置生命周期、定时合并小文件。
  5. 命名不统一:同字段多套名字、口径混乱;统一数仓建表规范、字段命名字典。

六、面试万能口述话术

建表我会严格遵循数仓规范,统一字段命名和类型,优先使用外部表、ORC 存储,合理设计分区分桶;同时完善表和字段注释,保证元数据完整。日常依赖元数据平台做资产管理、血缘分析、生命周期治理,提前评估表变更对下游的影响,保障数据口径统一、链路可追溯、方便后续维护和故障排查。

建 ORC 表 最容易遇到的问题 + 原因 + 解决方案(面试直接背)

全是工作真实踩坑,建表、导数据、查询必遇的问题,我给你按建表时、导数据后、查询时分好类,好记好用。

一、建表阶段容易踩的坑

1. 字段顺序、字段类型和原始数据对不上

现象:查出来全是 null、字段错位、数值乱码。

原因:ORC 是按物理列位置映射,不是按字段名匹配。

解决:建表字段顺序必须和入库数据顺序完全一致;不要随便调换字段位置。

2. 分隔符还按 Text 表去写,多余指定 row format

现象:导入数据后全是 null、整行挤在第一个字段。

原因ORC 是二进制列式存储,根本不需要分隔符,写了反而解析错乱。

解决:建 ORC 表不要加 row format delimited,去掉分隔符配置。

3. 盲目加复杂类型 array/map/struct

现象:Spark 写的 ORC,Hive 读不到、变成 null、解析报错。

原因:不同引擎对 ORC 复杂类型兼容不一致。

解决:能平铺成普通字段就别用复杂类型;必须用就统一引擎读写。

4. 忘记加压缩,存储占用暴增

现象:ORC 反而没比 Text 省空间。

原因:默认压缩没开。

解决:建表指定 ORC + Snappy/Gzip 压缩。

5. 直接建内部表

现象:误删表连带删掉 HDFS 原始数据,无法回溯。

解决:生产 ORC 一律建外部表

二、导入数据后出现的问题

1. 大量小 ORC 文件

现象:查询很慢、NameNode 压力大、任务卡顿。

原因:动态分区、频繁 insert、批量太小,每个分区就几行数据生成独立小 ORC 文件。

解决:控制动态分区数量、合并小文件、设置任务输出 reduce 个数。

2. 分区元数据和实际 ORC 文件不一致

现象:查分区查不到数据,或者查出来 null。

原因:手动删 HDFS ORC 文件、元数据还在;或者导了数据没修复分区。

解决:MSCK REPAIR TABLE 修复分区;不要手动删 HDFS 文件。

3. 空值、脏数据写入 ORC 后无法肉眼排查

现象:数据异常,但没法像 Text 那样 cat 看原始内容。

原因:ORC 二进制,不能直接文本查看。

解决:脏数据在入库前清洗,再落地 ORC;排查只能靠 SQL 抽样。

三、查询使用时遇到的问题

1. 改表结构后全表查 null

现象:新增字段、改字段类型、调换顺序,历史 ORC 数据全部读不出。

原因:ORC 物理列结构固化,元数据改了没用,底层文件结构没变。

解决:尽量不中途改表结构;要改必须全量重刷数据

2. 跨引擎读写 ORC 报错、字段错位

现象:Hive 建的 ORC,Spark 读异常;Spark 写的 ORC,Doris 同步异常。

原因:Hive/Spark 不同版本 ORC 编码格式略有差异。

解决:统一集群引擎版本;尽量同引擎写同引擎读

3. 分区过多导致查询扫描大量 ORC 碎片

现象:按天分区又按小时细分,成千上万个小 ORC 文件,查询巨慢。

解决:合并分区粒度,不要过度细分;配置分区生命周期自动清理冷数据。

4. 行组参数不合理,查询性能上不去

现象:明明是 ORC,查询速度没提升。

原因:行组大小默认不合理,索引没发挥作用。

解决:建表适当调 orc 行组参数,适配大宽表、大明细场景。

四、面试一句话背诵版

建 ORC 表常见问题有:字段顺序类型不匹配查出来全是 null、错误配置分隔符导致解析错乱、复杂类型跨引擎不兼容、容易产生大量小 ORC 文件、改表结构历史数据读不出、版本兼容解析异常、不能直接肉眼查脏数据、分区过多拖累查询性能

规范做法是:用外部表、不加分隔符、固定字段顺序、开启压缩、少用复杂类型、严控动态分区、定时合并小文件、不随意改表结构

ORC 小文件问题 完整版(原因 + 危害 + 怎么解决 + 面试背诵)

一、什么是 ORC 小文件

ORC 正常一个文件几百 MB 最优;

远小于正常大小(几 KB、几十 KB)的 ORC 文件,就是 ORC 小文件。

二、为什么 ORC 更容易产生小文件

  1. 动态分区

    每来一个分区就生成一个单独 ORC 文件,分区越多小文件越多。

  2. 微批次频繁写入

    Flink/Spark 每隔几秒写一次,每次数据量少,直接生成极小 ORC。

  3. Reduce 个数过多

    Hive/Spark 输出 reduce 太多,每个 reduce 输出一个小 ORC。

  4. 数据倾斜

    某个分区数据极少,单独生成一个空 / 少量数据 ORC 文件。

  5. 多次覆盖、增量追加

    反复 insert overwrite、insert into,碎片化生成大量零散 ORC。

  6. ORC 本身结构原因

    ORC 自带

    行组、索引、脚注

    ,哪怕只有几行数据也要存完整结构,文件再小也占元数据开销。

三、ORC 小文件带来的危害(面试必背)

  1. NameNode 压力爆炸

    每个小文件都占一条元数据,成千上万个小文件耗尽 NN 内存。

  2. 查询性能暴跌

    查一张表要打开成千上万个 ORC 文件,

    打开文件开销 > 计算开销

    ,查询很慢。

  3. ORC 索引失效

    小文件行组太少、索引冗余,完全发挥不了 ORC 索引优势。

  4. 集群任务调度变慢

    每个小文件都要启动一个 MapTask,任务启动耗时暴增。

  5. 占用存储变多

    ORC 文件本身有固定头部索引,文件越小

    冗余占比越高

    ,反而比 Text 更耗存储。

四、生产解决 ORC 小文件 7 种方案(面试直接说)

1. 合并小文件(最常用)

定时任务把同分区下大量小 ORC,重新写成大 ORC 文件

Hive:insert overwrite 重写分区

Spark:coalesce /repartition 控制输出文件数

2. 控制 Reduce 输出个数

写入前强制设置 reduce 数量,一个分区输出固定几个大文件,避免碎片化。

3. 禁止过度细分动态分区

不要按小时、渠道、设备这种多维度细分区,合并粗粒度分区

4. 写入前攒批、批量输出

实时任务攒够数据再落地,不要几秒写一次,减少小文件生成。

5. 参数调优合并

Hive/Spark 开启自动合并小文件参数,任务结束自动合并同分区碎片。

6. 合理设置 ORC 行组

行组大小适配数据量,避免极小行组产生碎片化文件。

7. 配置分区生命周期

过期分区自动清理,防止小文件日积月累越堆越多。

五、面试极简背诵版

ORC 小文件主要由动态分区过多、微批次频繁写入、reduce 个数过多、数据倾斜产生;

危害是压垮 NameNode、查询变慢、ORC 索引失效、任务启动开销大、存储冗余变高

解决方式:定时合并小文件、控制输出 reduce 数量、粗粒度分区、批量攒批写入、开启自动合并、配置生命周期

需要我给你一份 Hive/Spark 合并 ORC 小文件可直接运行 SQL 模板 吗?

ORC & Parquet 一页纸面试速背版(全覆盖,直接背完就能答题)

一、共同点

都是列式存储、二进制格式、压缩率高、只读不支持原地修改、支持 array/map/struct 复杂类型、适配大数据数仓

二、核心区别速记

  1. 出身

    ORC:Hive 社区自研,Hive 亲儿子

    Parquet:谷歌 + Spark 主导,跨引擎通用标准

  2. 索引

    ORC:自带行组、分片、布隆索引,过滤查询更快

    Parquet:无内置索引,依赖引擎本身过滤

  3. 压缩

    ORC:压缩率更高,更省存储空间

    Parquet:压缩略低,差距不大

  4. 兼容性

    ORC:跨引擎、跨版本兼容差,易字段错位、出 null

    Parquet:格式标准,跨引擎、跨版本极其稳定

  5. 生态适配

    ORC:适配纯 Hive 离线数仓

    Parquet:Spark/Flink/Doris/ 数据湖 Hudi、Iceberg 标配

  6. 小文件

    ORC:结构重、带索引,小文件问题更严重

    Parquet:结构轻,小文件影响更小

  7. 复杂类型

    ORC:Hive 内部稳,跨引擎容易解析异常

    Parquet:全引擎兼容稳定不翻车

三、坚决不能用 ORC 的场景

  1. Spark/Flink/Doris 多引擎互相读写
  2. 数据湖 Hudi、Iceberg 项目
  3. 复杂类型多、跨引擎流转
  4. 集群版本不统一、环境杂乱
  5. 实时频繁小批次写入(极易爆小文件)
  6. 经常增删字段、调整表结构

四、坚决不能用 Parquet 的场景

  1. 纯 Hive 离线大报表、超大流水表查询
  2. PB 级海量数据,极致节省存储成本
  3. 需要依赖行组索引、分片过滤加速查询
  4. 全程只在 Hive 内部流转,无跨引擎

五、生产选型口诀

纯 Hive 数仓要索引、高压缩 → 选 ORC

跨引擎、数据湖、实时混跑 → 选 Parquet

六、ORC 建表常见坑

  1. 不要加分隔符 row format,会解析错乱
  2. 字段顺序不能乱,按物理列位置匹配
  3. 改字段类型 / 顺序,历史数据全查 null
  4. 动态分区容易生成大量小 ORC 文件
  5. 二进制格式,无法 cat 肉眼看原始数据
  6. 跨引擎读写易字段错位、出空值

七、ORC 小文件原因 + 危害 + 解决

原因

动态分区过多、Reduce 数量太多、实时微批次频繁写入、数据倾斜、多次增量覆盖

危害

压垮 NameNode 元数据、查询打开大量文件变慢、ORC 索引失效、任务启动开销大、存储冗余变高

解决

定时合并小文件、控制输出 Reduce 个数、粗粒度分区、实时攒批写入、开启自动合并、配置分区生命周期

八、面试万能口述总结

ORC 是 Hive 社区专属列式存储,自带行组索引、压缩率更高,纯 Hive 离线大报表查询更快、更省存储;缺点是跨引擎兼容差、版本容易出问题、小文件更严重,还不能随便改字段顺序和类型。

Parquet 是谷歌 Spark 主导的通用列式标准,跨引擎跨版本特别稳,适配 Spark、Flink、Doris 和 Hudi/Iceberg 数据湖;但没有内置索引,压缩率比 ORC 稍低,纯 Hive 超大报表查询性能不如 ORC。

选型一句话

纯 Hive 离线数仓选 ORC;跨引擎、实时混跑、数据湖项目直接用 Parquet。

生产标准 ORC 外部表建表模板(可直接复制、开箱即用、避坑版)

模板 1:普通天分区 ORC 标准建表(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE EXTERNAL TABLE IF NOT EXISTS dwd_user_log_di (
user_id string COMMENT '用户ID',
device_id string COMMENT '设备ID',
page_name string COMMENT '页面名称',
event_type string COMMENT '事件类型',
os_type string COMMENT '系统类型',
create_time string COMMENT '创建时间'
)
COMMENT '用户行为日志明细日表'
PARTITIONED BY (dt string COMMENT '日期分区')
STORED AS ORC
TBLPROPERTIES (
'orc.compress' = 'SNAPPY',
'orc.row.index.stride' = '10000',
'orc.stripe.size' = '268435456',
'partition.lifetime.days' = '90',
'external.table.purge' = 'false'
);

模板 2:拉链表 ORC 标准建表(维度表专用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE EXTERNAL TABLE IF NOT EXISTS dim_user_zip (
user_id string COMMENT '用户ID',
user_name string COMMENT '用户名',
area_code string COMMENT '地区编码',
phone string COMMENT '手机号',
start_dt string COMMENT '生效日期',
end_dt string COMMENT '失效日期'
)
COMMENT '用户维度拉链表'
PARTITIONED BY (dt string COMMENT '分区日期')
STORED AS ORC
TBLPROPERTIES (
'orc.compress' = 'SNAPPY',
'orc.stripe.size' = '268435456',
'partition.lifetime.days' = '180'
);

模板 3:小时级分区 ORC 建表(实时落地专用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE EXTERNAL TABLE IF NOT EXISTS dwd_order_flow_hi (
order_id string COMMENT '订单ID',
user_id string COMMENT '用户ID',
goods_id string COMMENT '商品ID',
order_amount decimal(18,2) COMMENT '订单金额',
order_status string COMMENT '订单状态'
)
COMMENT '订单流水小时表'
PARTITIONED BY (dt string, hour string)
STORED AS ORC
TBLPROPERTIES (
'orc.compress' = 'SNAPPY',
'orc.row.index.stride' = '5000',
'partition.lifetime.days' = '30'
);

关键配置说明(面试 + 生产必懂)

  1. 必须加 EXTERNAL:生产一律外部表,删表不删 HDFS 数据。
  2. 不要写 row format:ORC 二进制,加分隔符直接解析全为 null。
  3. 压缩固定 SNAPPY:速度快、压缩率均衡,数仓标配。
  4. orc.stripe.size:行组分片 256M 左右,最优查询性能。
  5. partition.lifetime.days:自动过期清理,防止分区暴涨、小文件堆积。
  6. 金额字段用 decimal (18,2),绝不使用 double,避免精度丢失。

使用注意事项(避坑)

  1. 字段顺序固定不能乱,ORC 按物理列位置映射,乱序全查 null。
  2. 建完表不要随意增删字段、调换顺序,改结构必须全量重刷数据。
  3. 插入数据只用 insert overwrite/into,不要手动改 HDFS 文件。
  4. 动态分区配合此模板,记得控制分区数量,避免小 ORC 文件泛滥。

生产标准 Parquet 建表模板(可直接复制、跨引擎通用、避坑版)

模板 1:天分区 Parquet 通用明细表(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE EXTERNAL TABLE IF NOT EXISTS dwd_user_behavior_di (
user_id string COMMENT '用户ID',
device_id string COMMENT '设备ID',
page_url string COMMENT '页面地址',
event_name string COMMENT '事件名称',
app_version string COMMENT 'APP版本',
create_time string COMMENT '事件时间'
)
COMMENT '用户行为日志日明细表'
PARTITIONED BY (dt string COMMENT '日期分区')
STORED AS PARQUET
TBLPROPERTIES (
'parquet.compression' = 'SNAPPY',
'partition.lifetime.days' = '90',
'external.table.purge' = 'false'
);

模板 2:多引擎共用 Parquet 宽表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE EXTERNAL TABLE IF NOT EXISTS dws_user_summary_di (
user_id string COMMENT '用户ID',
login_cnt bigint COMMENT '登录次数',
order_cnt bigint COMMENT '下单次数',
total_amount decimal(18,2) COMMENT '累计金额',
first_login_dt string COMMENT '首次登录日期'
)
COMMENT '用户行为聚合宽表日表'
PARTITIONED BY (dt string COMMENT '日期分区')
STORED AS PARQUET
TBLPROPERTIES (
'parquet.compression' = 'SNAPPY',
'partition.lifetime.days' = '120'
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE EXTERNAL TABLE IF NOT EXISTS dwd_order_real_hi (
order_id string COMMENT '订单ID',
user_id string COMMENT '用户ID',
goods_id string COMMENT '商品ID',
order_amount decimal(18,2) COMMENT '订单金额',
pay_status string COMMENT '支付状态',
pay_time string COMMENT '支付时间'
)
COMMENT '实时订单流水小时表'
PARTITIONED BY (dt string, hour string)
STORED AS PARQUET
TBLPROPERTIES (
'parquet.compression' = 'SNAPPY',
'partition.lifetime.days' = '30'
);

模板 4:数据湖 Hudi/Iceberg 配套 Parquet 建表

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE EXTERNAL TABLE IF NOT EXISTS dwd_hudi_user_log_di (
user_id string COMMENT '用户ID',
event_type string COMMENT '事件类型',
device_os string COMMENT '操作系统',
raw_info string COMMENT '原始报文'
)
COMMENT 'Hudi用户行为明细表'
PARTITIONED BY (dt string)
STORED AS PARQUET
TBLPROPERTIES (
'parquet.compression' = 'SNAPPY',
'partition.lifetime.days' = '180'
);

Parquet 建表核心规范(必记)

  1. 一律 EXTERNAL 外部表,防止误删 HDFS 数据。
  2. 不要加 row format delimited,Parquet 二进制,加分隔符直接全查 null。
  3. 压缩统一用 SNAPPY,兼顾速度和压缩率,跨引擎通用。
  4. 金额必用 decimal(18,2),禁用 double 防止精度丢失。
  5. Parquet 跨引擎兼容强,字段顺序不严格卡死,但生产仍建议固定顺序。
  6. 配置 partition.lifetime.days 自动清理冷分区,控制小文件累积。

Parquet 适用场景口诀

Spark、Flink、Doris 跨引擎

数据湖 Hudi、Iceberg 一律用 Parquet

版本杂乱、复杂类型多 优先 Parquet

ORC vs Parquet 建表区别 + 面试常问点 极简一页背

一、建表语法相同点

  1. 都用 EXTERNAL 外部表(生产必用)
  2. 不能写 row format delimited 分隔符(二进制列式,写了全 null)
  3. 都支持 分区、注释、TBLPROPERTIES
  4. 金额都用 decimal(18,2),不用 double
  5. 压缩标配都是 SNAPPY

二、建表语法不同点

项目 ORC Parquet
存储写法 STORED AS ORC STORED AS PARQUET
压缩参数 orc.compress parquet.compression
独有参数 可配置行组、条纹大小 orc.stripe.size 无额外索引参数,默认即可
字段顺序 严格按物理位置,乱序查全 null 按字段名匹配,顺序不敏感

三、建表时最大坑区别

ORC 建表必避坑

  1. 字段顺序绝对不能乱,改结构必须重刷全量
  2. 不能随便增删字段、调换位置
  3. 极易产生小文件,建表务必配分区生命周期
  4. 跨引擎读写容易字段错位、出 null

Parquet 建表必避坑

  1. 无内置索引,大宽表别指望靠格式提速
  2. 虽然顺序不敏感,但生产也要固定字段顺序规范
  3. 不适合纯 Hive 超大报表、极致省存储场景

四、建表选型口诀

  • 纯 Hive、要索引、高压缩、离线大报表 → 建 ORC
  • Spark/Flink/Doris 跨引擎、数据湖 Hudi/Iceberg → 建 Parquet
  • 实时小批次写入、版本环境杂乱 → 优先 Parquet
  • 经常改表结构、增删字段 → 别用 ORC,用 Parquet

五、面试高频问答(直接背)

1. ORC 和 Parquet 建表最大区别是什么?

语法差不多,主要差异:ORC 字段顺序严格绑定物理位置、自带索引可配置行组参数;Parquet 按字段名匹配、顺序不敏感、无内置索引,跨引擎兼容更好

2. 为什么建 ORC 不能随便改字段顺序?

ORC 是列式物理存储,按列位置映射,不是按字段名;改顺序或类型,历史文件解析错位,查询全是 null,必须全量重刷数据。

3. 建列式表为什么不能加 row format 分隔符?

ORC/Parquet 都是二进制列式存储,不是文本行格式,加分隔符会解析错乱,所有字段都查成 null。

4. 生产为什么都用外部表?

外部表删表只删元数据,不删 HDFS 原始数据;防止误删、方便回溯复用,生产禁止用内部表。

5. 建 ORC/Parquet 必加什么配置?

必开 SNAPPY 压缩、配置 分区生命周期、一律外部表、加全字段注释。

数据集市(Data Mart)是数据仓库领域的一个核心概念,也是数据工程师、数据分析师面试中的高频考点。下面我会先为你系统地介绍数据集市,然后梳理面试中需要掌握的关键问题。


介绍下数据集市,及面试中需要掌握的问题

一、什么是数据集市?

数据集市是一种面向特定业务主题或用户群体的、经过聚合和优化的数据存储集合。可以把它理解为一个“小型、聚焦的数据仓库”,通常服务于某个部门(如销售、市场、财务)或某类特定分析需求。

核心特点

  • 主题导向:围绕一个业务主题(如销售、库存、客户)构建,而非企业全局。
  • 部门级别:通常由一个部门或团队拥有和使用,数据量远小于企业级数据仓库(EDW)。
  • 预聚合/汇总:为了提升查询性能,常包含预先计算好的汇总数据(如月度销售额)。
  • 快速实现:相比企业级数据仓库,建设周期短、成本低、技术栈灵活。
  • 数据来源:多数情况从企业数据仓库(EDW)抽取相关数据;也可直接从业务系统或外部数据源构建(即“独立数据集市”)。

二、数据集市与数据仓库的关系

对比维度 数据仓库(EDW) 数据集市
范围 企业级,全主题 部门级,单主题
数据粒度 细粒度(原子数据) 轻量汇总/聚合
建模方法 通常采用 Inmon(范式建模) 通常采用 Kimball(星型/雪花型)
更新频率 批量 ETL(小时/天) 可更高频或相同节奏
用户群体 全公司数据分析师 特定部门业务人员
存储容量 TB~PB 级 GB~TB 级

经典架构模式

  1. 独立数据集市:完全不依赖 EDW,直接从源系统构建,适合局部需求,但易导致数据孤岛。
  2. 从属数据集市:数据来源于 EDW,保证一致性和重用性,是更推荐的做法。

三、数据集市的常见误区与最佳实践

❌ 常见误区

  • 数据集市 = 数据库中的一张表(错,它是一组面向分析的表)
  • 独立数据集市可以取代数据仓库(容易形成孤岛且重复建设)
  • 数据集市不需要数据清洗(仍需保证质量)

✅ 最佳实践

  • 数据仓库承担“中央厨房”角色,数据集市作为“成品菜”提供给业务用户。
  • 统一维度和指标口径,避免不同数据集市出现同名不同义的情况。
  • 使用合适的建模方式:星型模型(一张事实表+多张维度表)最常用,兼顾性能和易用性。
  • 可以配合视图、物化视图或 BI 工具中的逻辑数据集市进行快速迭代。

四、面试中需要掌握的问题及解答要点

下面是针对数据集市的常考面试题,你可以按这些问题来准备:

1. 简单介绍数据集市?它与数据仓库的区别?

要点:数据集市是部门级、面向主题的数据子集;数据仓库是企业级、面向全局的。区别围绕范围、粒度、用户、建设成本等。

2. 什么时候应该建数据集市?什么时候不应该?

应建:业务部门有独立分析需求、对查询性能要求高、希望快速看到成效、避免影响 EDW 负载。
不应建:数据量很小可以直接查询、需求还不明确、团队没有能力维护。

3. 数据集市的设计步骤有哪些?

步骤
① 确定业务主题(如销售分析)
② 定义事实和维度
③ 确定粒度(如每笔订单明细)
④ 设计事实表和维度表(星型/雪花型)
⑤ 确定数据来源(从 EDW 或业务库)
⑥ 设计 ETL 流程并实施。

4. 星型模型和雪花型模型在数据集市中如何选择?

星型模型:冗余维度属性,查询性能好,用于对查询速度要求高的场景。
雪花型:规范维度表,节省存储,但多表 join 可能较慢。
数据集中通常首选星型,因为更直观、高效。

5. 如何处理数据集市的变化(比如增加新维度或指标)?

策略

  • 增加新维度表:不影响现有数据。
  • 增加新指标:在事实表中新增列,历史数据回填或设为 NULL。
  • 慎用对已有字段的变更,一般采用新增而非修改。

6. 数据集市如何保证和 EDW 数据一致性?

措施

  • ETL 中明确过滤规则和转换逻辑。
  • 使用统一的度量定义口径(比如销售额的统计规则)。
  • 建立数据血缘和元数据管理,定期进行数据质量校验。

7. 你能举一个实际工作中设计数据集市的例子吗?

示例(可依自身经历改编):
“在零售公司,销售部门需要按日查看各门店、各品类销售额和毛利。我从 EDW 抽取订单明细和门店、商品维度,以订单子单粒度构建事实表,聚合出每日销售汇总,建成销售数据集市。查询速度从原来的分钟级下降到秒级,业务人员直接用 Tableau 连接。”

8. 数据集市与传统报表有什么区别?

报表是最终展现形式,数据集市是支撑报表和即席查询的数据结构。数据集市可以产出多张报表。

9. 如果业务人员想自己建数据集市,数据团队如何管控?

可提供共享的数据沙盒环境,制定数据使用规范,通过工具实现自助 ETL,同时监控数据质量。

10. 数据湖、数据仓库、数据集市三者结构

示意图
业务系统 → (数据湖:原始数据)→ (数据仓库:清洗/集成后的企业级数据)→ (数据集市:部门汇总数据)→ 报表/BI。

如何保证数据集市与数据仓库的一致性

保证数据集市(Data Mart)与数据仓库(EDW)之间的一致性,是数据架构中的核心工程实践问题。下面我会从架构原则、技术手段、管理流程三个层面,系统性地给出解决方案。


一、明确“一致性”的内涵

在讨论方法前,需要先明确一致性具体指什么,通常包括:

  • 数据内容一致:同一业务指标(如“昨日销售额”)在 EDW 和数据集市中查询结果相同。
  • 口径定义一致:维度和指标的业务含义、计算逻辑相同,无同名不同义或同义不同名。
  • 数据时效一致:数据更新频率与延迟在可接受范围内保持一致(如 T+1 的数据集市在早上 8 点前与 EDW 同步完成)。
  • 数据结构兼容:关键字段类型、长度、枚举值等定义相同,避免因类型转换导致异常。

二、架构原则:从属数据集市是基础

强制要求:所有面向部门的数据集市的数据必须源自 EDW,而不是直接从业务源系统或外部数据拉取。

  • 从属数据集市:数据源为 EDW,经过过滤、聚合、转换后形成。这样 EDW 作为唯一可信版本,天然保证了基础数据的一致性。
  • 避免独立数据集市:独立数据集市从源系统直接构建,很容易与 EDW 口径不同,形成数据孤岛和“多头马车”。

从属数据集市的结构如图:
业务源 → ODS → EDW(企业级统一模型) → 数据集市(部门级/主题级) → BI/报表


三、技术手段:从 ETL 到数据质量校验

1. 复用 EDW 的 ETL 逻辑

  • 数据集市的 ETL(或 ELT)复用 EDW 层的加工逻辑。例如 EDW 中定义好“净销售额 = 订单金额 - 退款金额 - 折扣”,数据集市直接引用该字段,而不是重新计算。
  • 使用视图(view)物化视图(materialized view) 作为数据集市的数据源,这样当 EDW 底层逻辑变化时,数据集市会自动继承变更。

2. 统一维度和指标的定义

  • 建立企业级维表(如日期维度、产品维度、客户维度)并复用。数据集市中的维表使用与 EDW 同一份维表,避免维度代码不同步。
  • 对于指标,使用指标字典统一定义,在 ETL 过程中通过配置表或函数保证同一指标的计算公式完全一致。

3. 数据同步机制

  • 批量同步:每天在固定时间窗口(如夜间业务低峰期)从 EDW 增量或全量刷新数据集市。
    • 增量同步:使用 last_modify_timeetl_date 分区,只抽取变化的数据。
    • 全量刷新:适用于小表或必须完全重建的场景。
  • 实时/准实时:若业务要求高时效,可采用 binlog 或 change data capture (CDC) 从 EDW 出发同步,但注意此时 EDW 本身也可能是近实时的。

4. 数据质量校验

在数据加载完成后,运行自动化检查任务,确保一致性:

  • 记录数核对:对比 EDW 源表与数据集市目的表的记录数差异(允许聚合造成的行数变化,则对比聚合前的基础记录)。
  • 关键指标比对:选取几个核心指标(如总销售额、总数量),在 EDW 源层和集市层分别计算,允许差异为0或极小阈值。
  • 异常检测:检查数据集市中的 NULL 率、唯一键重复、数据分布(如最大值、最小值)是否与 EDW 一致。
  • 血缘追踪:使用元数据管理工具(如 Atlas、DataHub)记录每条集市数据的来源表、加工逻辑,便于定位不一致原因。

5. 自动化调度与监控

  • 使用任务调度系统(如 DolphinScheduler、Airflow)组织 ETL 依赖关系:EDW 加工完成 → 触发数据集市任务 → 任务完成后触发质量校验 → 校验通过才允许 BI 报表刷新。
  • 建立告警:当一致性校验失败时,向数据团队发送邮件、钉钉或短信告警,暂停下游任务。

四、管理流程:变更管理与口径治理

1. 变更影响分析

  • 当 EDW 的表结构、计算逻辑或数据源发生变更时,必须通过变更管理平台(如 Jira 加数据 Catalog)自动识别受影响的数集市。
  • 执行回测:在测试环境运行数据集市任务,对比变更前后的结果是否一致。

2. 统一的发布周期

  • 数据集市与 EDW 的版本同步发布,避免 EDW 线上已更新而数据集市仍使用旧代码,导致数据跑空或错乱。

3. 数据 Owner 机制

  • 每个数据域(如销售、库存)指定数据 Owner,由 Owner 审批数据集市定义及变更,确保口径一致性。

4. 文档和元数据管理

  • 维护数据字典指标口径ETL 映射文档,并在代码注释或数据平台中固化,形成可执行的元数据(例如 dbt 的 yaml 定义)。

五、示例:日常操作中的标准流程

以“销售数据集市”为例,描述一天的一致性保障操作:

  1. 凌晨 03:00:EDW 加工完成,将前一天的订单明细写入 dw.fact_sales_daily 分区。
  2. 凌晨 04:00:数据集市 ETL 启动,从 dw.fact_sales_daily 读取数据,按店铺、商品 category 聚合后写入 dm.sales_summary_daily
  3. 凌晨 04:30:数据质量任务执行以下校验:
    • 对比 dw.fact_sales_dailydm.sales_summary_daily 的日总销售额总和,差异为 0 才通过。
    • 检查聚合后的行数与预期范围是否合理。
  4. 凌晨 05:00:所有校验通过,触发 BI 报表数据刷新;若校验失败,则告警并停止下游任务,人工介入排查(常见原因:EDW 生成失败、数据集市代码逻辑错误)。

六、常用工具推荐

类别 工具示例
数据仓库/数据集市平台 Hive、MaxCompute、Snowflake、BigQuery、Redshift
ETL/调度 DolphinScheduler、Airflow、DataWorks、Talend
数据质量 Great Expectations、Soda、DataQuality
元数据与血缘 Apache Atlas、DataHub、Amundsen、dbt docs

七、总结

保证数据集市与数据仓库一致性的黄金法则

  1. 架构上:强制从属数据集市,不建独立集市。
  2. 技术上:复用逻辑 + 数据校验 + 自动化监控。
  3. 管理上:统一口径 + 变更联动 + 数据 Owner 制。

在实际面试中,你可以重点强调**“从属数据集市”“自动化一致性测试”**两个最关键的实践点,并结合自己工作中的实际案例(例如某次因为不一致导致报表出错,后来增加质量校验解决的经历)来增强说服力。

SCD Type1和Type2

在数据仓库的维度表设计中,缓慢变化维度 是描述那些会随时间变化,但变化频率不高且不可预测的属性(如用户的邮箱、会员等级、地址等)。处理这些变化,主要有两种经典策略:SCD Type 1SCD Type 2

简单来说,两者的核心区别是:要不要保留历史


SCD Type 1:直接覆盖,不记历史

实现方式

当维度属性发生变化时,直接 UPDATE 原记录,用新值覆盖旧值。

特点

  • 简单、高效:无额外字段,无需增加行,存储成本低。
  • 历史丢失:无法知道这个属性在过去的任何时间点是什么值。

典型场景

  • 修正确实是错误的数据(比如录入错误的生日、错误的联系电话)。
  • 业务明确表示不关心历史变化(如商品的分类标签偶尔调整,但无需追溯)。

例子

用户“张三”的会员等级从“黄金”变成“铂金”。

user_id user_name membership_level
1001 张三 黄金 (更新前)

执行 Type 1 后:

user_id user_name membership_level
1001 张三 铂金 (旧值被覆盖)

结果:历史“黄金”状态永久丢失。如果分析去年某段时间的活动,张三在本应该是黄金会员的记录中也会被显示为铂金,导致统计口径错误。


SCD Type 2:增加行,保留完整历史

实现方式

当维度属性发生变化时,不修改原有记录,而是 新增一行。为了区分哪一行是当前值,通常会增加三个辅助字段:

  • start_date:该版本记录开始生效的日期(或时间戳)。
  • end_date:该版本记录失效的日期,当前版本的 end_date 通常设为 9999-12-31NULL
  • is_current:标志位,1 表示当前有效版本,0 表示历史版本。

特点

  • 完整的历史追溯能力:可以查询任意时间点的属性状态。
  • 存储会增加:随着属性变化次数增加,维度表行数会增长。
  • 查询稍复杂:通常需要加入 is_current = 1 条件才能获取当前最新状态。

例子

还是“张三”的会员等级从“黄金”变成“铂金”,变化发生在 2025-01-10。

变化前的记录(只有一条)

user_id user_name membership_level start_date end_date is_current
1001 张三 黄金 2024-01-01 9999-12-31 1

执行 Type 2 后

  1. 关闭旧记录:将原来那条记录的 end_date 改为变化当天(或前一天),is_current 改为 0。
  2. 插入新记录:插入一条新记录,start_date 为变化当天,end_date 为遥远未来,is_current 为 1。
user_id user_name membership_level start_date end_date is_current
1001 张三 黄金 2024-01-01 2025-01-09 0
1001 张三 铂金 2025-01-10 9999-12-31 1

结果:当分析 2024 年的订单时,可以通过关联 end_date 条件,关联到“黄金”这条记录;分析 2025 年 1 月 10 日之后的订单时,则会关联到“铂金”记录。历史完全保留。


Type1 vs Type2 对比总结

对比项 SCD Type 1 SCD Type 2
处理方式 UPDATE 原行 新增行,关闭旧行
历史保留 ❌ 不保留 ✅ 完整保留
存储空间 无额外占用 随变化次数增长
查询当前状态 简单 (直接读取) 需要过滤 is_current = 1
查询历史状态 不可能 需要关联 start_date/end_date
实现复杂度 较高
典型场景 修正错误数据、不关心历史 用户等级、地址、合同状态等需要历史追溯

扩展:其他 Type 简介

  • SCD Type 0:保留原始值,永远不变(如用户注册时的原始注册日期)。
  • SCD Type 3:增加新列保存“上一个值”,只能保留一次变化(如同时有 current_phoneprevious_phone)。
  • SCD Type 4:将快速变化的属性单独拆成微型维度表。
  • SCD Type 6:混合 Type 1、2、3,既有历史行,又有当前列。

💎 总结

  • 选 Type 1:当业务说“我们不需要知道过去是什么样子的,只要最新的就行”。
  • 选 Type 2:当业务问“上个月这个时候用户的等级是什么?”、“去年年底他的地址是哪里?”这类问题时,就是 Type 2 出场的时候。

在实际数仓项目中,维度的不同属性可能会选择不同策略,比如“姓名”用 Type 2,“生日”用 Type 1(生日不应该变,变了说明录入错误可以直接覆盖)。

hive建表多字段分区注意事项

在 Hive 中,多字段分区(即多个分区列)是一种常见的数据组织方式,可以显著提升查询效率。但使用不当也会带来性能和管理问题。以下是主要的注意事项及最佳实践。


1. 分区顺序非常重要

分区字段的顺序决定了 HDFS 上的目录层级。例如:

1
PARTITIONED BY (dt STRING, hour STRING, region STRING)

对应的 HDFS 路径为:/table/dt=20250512/hour=10/region=cn/

注意事项

  • 过滤频率最高、基数适中的字段放在前面(如 dt),因为查询时通常优先按日期过滤。
  • 低基数但查询频繁的字段(如 region)放在靠后位置,可以减少底层目录数量。
  • 避免将高基数字段(如 user_id)作为分区字段,否则会产生大量小分区,导致元数据爆炸和 NameNode 压力。

2. 控制分区总数,避免元数据膨胀

每个分区在 Hive 元数据中对应一条记录,分区过多会导致:

  • Metastore 查询变慢(如 SHOW PARTITIONS 耗时很长)
  • 作业启动时扫描分区耗时增加
  • HDFS 小文件问题(如果每个分区下文件过多)

最佳实践

  • 分区总数建议控制在 5 万以内(根据集群规模调整)。
  • 若单分区文件数过多,可在分区下进一步使用 分桶(CLUSTERED BY) 来优化。
  • 对于时间序列数据,可考虑按月或周分区,而非按天,以减少总分区数。

3. 分区字段的数据类型选择

Hive 分区列在底层以目录名形式存储,因此支持的数据类型有限:

  • 常用:STRINGINTBIGINTDATE
  • 避免使用:DECIMALTIMESTAMP(可能引起精度或时区问题)
  • 绝不能用:复杂类型(MAPSTRUCTARRAY

示例

1
2
3
4
5
-- 推荐
PARTITIONED BY (dt STRING, hour INT)

-- 不推荐
PARTITIONED BY (created_at TIMESTAMP) -- 目录名包含冒号等特殊字符

4. 动态分区写入注意事项

当使用动态分区插入数据时(INSERT OVERWRITE TABLE ... PARTITION(dt, hour)):

  • 开启动态分区模式:

    1
    2
    SET hive.exec.dynamic.partition=true;
    SET hive.exec.dynamic.partition.mode=nonstrict;
  • 注意项

    • 动态分区会依据 SELECT 最后几列的顺序来确定分区值,必须与 PARTITION 子句中的字段顺序一致。
    • 避免产生过多动态分区(可设置 hive.exec.max.dynamic.partitions=1000 等参数),否则可能报错。
    • 若某分区列值为 NULL 或空字符串,Hive 会创建一个特殊分区 __HIVE_DEFAULT_PARTITION__,通常需要避免(可提前过滤)。

5. 分区裁剪与查询效率

多字段分区只有在查询条件包含完整的前缀列时才能生效。

  • 例如分区结构 (dt, hour, region)
    • WHERE dt = '20250512' AND hour = '10' → 分区裁剪有效
    • WHERE dt = '20250512' → 可以裁剪到 dt 级别
    • WHERE hour = '10'无法裁剪,会全表扫描

建议

  • 总是将最常用的过滤字段放在分区前缀。
  • 如果业务经常跨过 dt 查询,考虑重新设计分区策略(如只按 dt 分区,把 hour 作为普通字段)。

6. 分区字段不建议与表字段重复

分区列在物理上并不存储在数据文件中,但逻辑上可以作为表的一个「虚拟列」。不要在表字段中再重复定义分区列

sql

复制下载

1
2
3
4
5
-- 错误示例
CREATE TABLE t (id INT, dt STRING) PARTITIONED BY (dt STRING);

-- 正确写法
CREATE TABLE t (id INT) PARTITIONED BY (dt STRING);

7. 处理数据倾斜

多字段分区可能因某个分区键值分布不均导致数据倾斜(例如按 region 分区,某个大城市数据量巨大)。

  • 可结合 分桶 缓解倾斜:CLUSTERED BY (user_id) INTO 256 BUCKETS
  • 或者在 ETL 中使用 DISTRIBUTE BY 随机打散。

8. 维护操作注意事项

  • 删除分区ALTER TABLE t DROP PARTITION (dt='20250512', hour='10'); 会删除对应 HDFS 目录及数据,不可逆。
  • 修复分区:若手动添加 HDFS 目录,需执行 MSCK REPAIR TABLE t; 同步元数据。该操作在大分区表上非常耗时。
  • 查看分区SHOW PARTITIONS t; 若分区过多,可加过滤条件:SHOW PARTITIONS t PARTITION(dt='20250512');

9. 多字段分区的替代方案

如果分区字段过多导致层级过深(如 5 层),可考虑:

  • 使用 嵌套分区 + 分桶 组合。
  • 将部分维度下沉到普通字段,仅保留必要的 2~3 个分区列。
  • 使用 IcebergHudi 等数据湖格式,支持更灵活的隐藏分区和丰富的索引,对多字段分区更友好。

10. 示例:合理的多字段分区建表

sql

复制下载

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE order_detail (
order_id BIGINT,
user_id BIGINT,
amount DECIMAL(10,2),
order_status STRING
)
PARTITIONED BY (
dt STRING COMMENT '分区日期 yyyyMMdd',
region STRING COMMENT '区域 cn/us/eu'
)
STORED AS ORC
TBLPROPERTIES ('orc.compress'='SNAPPY');

写入数据示例(动态分区)

sql

复制下载

1
2
3
4
5
6
INSERT OVERWRITE TABLE order_detail PARTITION(dt, region)
SELECT
order_id, user_id, amount, order_status,
DATE_FORMAT(created_at, 'yyyyMMdd') AS dt,
region
FROM raw_orders;

总结表格

注意事项 说明
顺序 高频低基数字段在前,避免高基数作为分区
总数 控制分区数 ≤ 5万,避免元数据膨胀
类型 使用 STRING/INT/DATE,不用复杂类型
动态分区 开启参数,避免产生默认分区
查询剪裁 条件必须包含前导分区字段
冗余字段 表中不重复定义分区列
数据倾斜 配合分桶或打散键
维护 删除/修复分区谨慎操作
替代方案 分区过多时可考虑湖格式

合理设计多字段分区能极大提升 Hive 查询性能,但需要权衡分区粒度、元数据成本和查询模式。

热点key单独join

对于热点Key,直接增加计算资源通常收效甚微,这是因为,分布式计算的核心逻辑是把数据拆成小块均衡分发到不同节点,大家一起算才快**-。热点Key的本质是数据分布极度不均,导致大量相同的Key涌向同一个节点,单个节点负载过重而其他节点闲置**-。单纯添加资源只是让这个核心瓶颈点“更强”(比如增加内存或CPU),但无法让这个“单点任务”拆分开,导致整个系统处理完这个最慢的节点后,才能获取全部结果**-。

因此,解决思路是对热点Key本身进行逻辑上的拆分,将其打散到多个节点。以下是一些常用的优化策略:

📈 五种主流的优化方案

🧂 方案一:加盐 (Salting) 与二次聚合

为热点Key增加一个随机前缀将其打散成多个子Key,完成局部Join后再去掉前缀进行全局聚合,从而分散压力–。

  • 实现方式:例如,为原本的Key增加一个0到N的随机数,变成(RandomNum + '_' + Key)。对大表处理后,小表也要做对应的扩容处理(例如复制N份,并加上相应的随机前缀)以保证能正确关联。注意,必须保证左右表的加盐逻辑完全一致-。
  • 适用场景:适用于热点Key在两张表中数据量都很大,且无法通过广播小表来解决的场景。
  • 优点:彻底打散热点,效果显著。
  • 缺点:实现逻辑稍复杂,需要处理中间状态的聚合,且可能导致数据膨胀。

✂️ 方案二:手动拆分与合并 (Split & Union)

将数据拆分为“热点数据”和“非热点数据”两路,分别用不同方式处理后再合并结果–。

  • 实现方式:例如,对于热点Key(如北京地区的用户)采用MapJoin(小表广播)等方式快速关联;对于非热点数据则使用普通的Reduce Join,最终用UNION ALL合并结果–(右表也是需要拆分成热点数据和非热点的,如果右表的热点数据足够小,可以使用mapjoin,那么就可以用这种方案)。
  • 适用场景:热点Key数量很少且已知,无法通过简单加盐处理时(例如,某个企业的ID)。
  • 优点:针对性强,可以隔绝热点Key对其他数据的影响。
  • 缺点:需要业务上知道哪些是热点Key,不够自动化。

⚪ 方案三:过滤与清理无效数据

很多数据倾斜是由NULL值或空值造成的,这些值大量聚集或被分发到同一个Task,导致处理缓慢。

  • 实现方式:在不影响业务逻辑的前提下,直接通过WHERE条件过滤掉这些无意义的Key-。如果无法过滤,可以尝试给NULL值添加随机数或替换为有业务意义的默认值-。
  • 适用场景:倾斜是由Join Key为NULL、空字符串等无业务含义的值引起的。
  • 优点:实现简单,效果立竿见影。
  • 缺点:需要评估过滤数据对最终结果的准确性是否有影响。

🧬 方案四:数据预处理与分桶优化

在数据进入Join阶段前,先进行聚合(Reduce数据量)或优化存储,从而在源头减少数据量。

  • 实现方式:如果Join的目的是聚合,可以先对两张表按Key做GROUP BY预聚合,再进行Join。通过CLUSTER BYDISTRIBUTE BY等语法提前对数据进行合理分区,避免Shuffle阶段的数据倾斜。利用列式存储(如ORC/Parquet)和谓词下推特性,减少无效IO。

⚙️ 方案五:利用计算引擎的现有优化特性

现代的计算引擎提供了许多开箱即用的特性来应对数据倾斜,优先开启它们可以减少手工优化的工作量。

  • Apache Spark:建议开启AQE(Adaptive Query Execution)特性,并启用倾斜Join优化,Spark会在运行时自动处理倾斜–。
  • Apache Flink:在处理维表Join时,可开启异步IO减少阻塞-。对于聚合操作,开启Local-Global(Mini-batch)优化可以在上游进行预聚合-。
  • 其他系统:阿里云的MaxCompute等平台也提供了SKEWJOIN HINT,允许手动指定热点Key进行优化-。

💎 总结

总之,解决热点Key导致的数据倾斜,核心思路是“打散”和“隔离”,而非简单地堆加资源。

你可以根据实际情况,按建议的优先级尝试解决方案:

  1. 优先开启引擎自动优化(如Spark AQE或Flink Local-Global):
    • 对于Spark平台,启用AQE和倾斜Join优化–。
    • 对于Flink平台,开启异步IO和Local-Global聚合–。
  2. 若自动优化不彻底:再尝试手动加盐拆分热点(需注意加盐逻辑一致性)-。
  3. 若场景特殊:可考虑手动拆分逻辑并合并非热点数据–,或直接过滤清理无效数据减轻负担-。

开启倾斜自动优化可能遇到的问题

开启倾斜自动优化,其本意是好的,但在实际生产中,它也常常有自己的“小脾气”。理解这些可能出现的问题,才能更好地驾驭它。

🕵️ 为什么优化可能不生效?(Spark AQE 高频失效场景)

在 Spark AQE 中,倾斜自动优化是大家最为关注的特性,但以下情况可能导致它“视而不见”:

  • 功能冲突被屏蔽:AQE 特性与 DPP 同时开启时,SparkSQL 任务执行中会优先执行 DPP,导致 AQE 不生效,需要手动关闭 DPP--1
  • 阈值设置不当:优化器依赖 spark.sql.adaptive.skewJoin.skewedPartitionFactorspark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes 判断数据倾斜-1。如果阈值设得太高,可能漏判;设得太低,则可能误判(过度优化)。
  • 分区数量超限:当要 Join 的两个 DataFrame 分区数超过 2000 时,统计信息可能无法精确反映数据分布,导致 AQE 无法识别出倾斜分区--11
  • 被不准确的统计信息误导:过时的表统计信息可能导致 Spark 误判数据量大小,进而放弃Broadcast Join,使得 AQE 的倾斜优化也不生效--12
  • 倾斜源头在热Key:AQE 的分区拆分机制在处理由“热 Key”引发的倾斜时存在盲区。例如当倾斜由少量高频出现的Key值引起时,AQE 只能看到数据量,看不到Key的频率--7
  • 受限于Join类型:对于 Left Outer Join,AQE 无法处理右侧(右表)的数据倾斜,只能处理左侧(左表)的情况-5
  • 被其他操作干扰:如果 Join 的一侧存在 AggWindow 等算子,因其对数据分布有特殊要求,可能会限制 AQE 的优化效果-5。使用缓存时也可能导致 AQE 失效-。

💥 潜在副作用与额外开销

自动优化在生效时,本身也可能带来一些性能开销:

  • 轻微误判“波及无辜”:可能有5%-10%非热点数据被误判参与拆分,带来不必要的额外开销。
  • 计划生成耗时增加:切分本身会带来额外的计划生成开销。在极端情况下,生成执行计划的时间可能超过1小时-,且并行度过大会增加调度开销,整体拉慢任务-。
  • 引发 OOM:部分案例表明 AQE 未触发优化时,强行增加并行度可能导致数据膨胀,引发内存溢出 (OOM)。
  • Join 策略回退:当AQE倾斜优化无法满足条件时,会退化成 SortMergeJoin。如果此时有表本可进行 Broadcast Join,Spark 也可能放弃广播而选择性能更差的 SortMergeJoin-。

Flink 目前没有Spark AQE那样内置的倾斜自动优化,遇到倾斜更多依赖手动干预或特定 API:

  • Flink 流场景下的常见原因:数据倾斜常源于 keyBy 分组时Key分布不均(如某个省份流量过大)、Kafka Topic源分区数据不均或 GROUP BY 聚合热点Key--19
  • Flink 的优化局限与手动干预
    • Local-Global (MiniBatch) 优化(推荐):是 Flink 解决数据倾斜最有效的特性。它先将数据在上游节点本地聚合 (Local),再发送到下游节点全局汇总 (Global),能大幅降低倾斜影响--20。通常开启 table.exec.mini-batch.enabled 并设置 table.optimizer.agg-phase-strategy = TWO_PHASE -20
    • 手动干预:当自动优化不足时,Flink 提供了手动方案,例如使用 rebalance() 强制数据均匀重分发-19、调整 keyBy 并行度-或对Key加盐打散-19

💎 总结:理智看待“自动优化”

倾斜自动优化技术是Spark和Flink中强大的工具,但在实际生产中,我们需要清楚它的边界。“自动”不等于“全能”,当它失效或效果不佳时,通常意味着我们需要回归到手动调优的思路上:打散热点Key、优化数据分布、调整Join顺序。把自动优化看作第一道防线,而手动调优则是最终的兜底方案。

待丰富问题

  1. 如何做数据质量监控报警
  2. 缓慢变化维的拉链表如何设计具体实现
  3. 动态分区可能遇到的问题
  4. 分桶可能遇到的问题及注意事项
  5. 使用orc和parquet需要注意的问题

实时数据仓库

实时数仓 CDC 增量同步 通俗 + 面试标准解释

一、先大白话一句话

CDC = Change Data Capture 变更数据捕获

就是不用全量导表,实时监听 MySQL 等库的 增、删、改 操作,只把变化的数据同步到实时数仓,这就叫 CDC 增量同步

二、原理通俗版

  1. MySQL 会把所有 insert/update/delete 记录写到 Binlog 二进制日志里;
  2. CDC 工具(Canal、Debezium、Flink CDC)实时监听 Binlog,只抓变化数据;
  3. 把变更数据实时发到 Kafka
  4. Flink 消费 Kafka,做清洗、关联、聚合,写入实时数仓(Doris/ClickHouse/Hive);
  5. 全程只同步增量变化,不跑全量,延迟秒级

三、CDC 三种实现方式

  1. 轮询查询:定时查增量字段,性能差、有延迟,老旧方案

  2. 触发器:数据库建触发器,影响业务性能,不推荐

  3. Binlog 监听

    (生产主流):

    Canal / Debezium /

    Flink CDC

    直接监听 Binlog,

    无侵入、低延迟、不影响业务

四、实时数仓 CDC 标准链路

MySQL → Flink CDC/Canal → Kafka → Flink 实时清洗加工 → 实时数仓 (Doris/CK/Hudi)

五、为什么要用 CDC 增量同步

  1. 不用全量同步,不用凌晨批量导数据,节省资源
  2. 实时秒级延迟,适合实时报表、大屏、用户画像
  3. 只同步变化数据,带宽、存储、计算开销极小
  4. 能同时捕获 Insert/Update/Delete 所有变更
  5. 对原业务库无侵入,不影响线上 MySQL 性能

六、实时数仓里 CDC 能干什么

  • 业务库数据实时入 ODS 层
  • 增量同步做维度表实时关联
  • 订单、交易、用户行为 实时入仓
  • 数据湖 Hudi/Paimon 增量入湖
  • 替代传统 DataX 全量定时同步

七、面试标准口述版

实时数仓 CDC 增量同步,就是通过 Flink CDC/Canal 监听 MySQL 的 Binlog 日志,实时捕获数据库的增删改变更数据,只同步增量变化而非全量表;

变更数据先写入 Kafka 做削峰解耦,再由 Flink 实时消费清洗、维度关联、分层加工,最终同步到 Doris/ClickHouse 等实时数仓;

相比传统定时全量同步,CDC 增量同步延迟低、资源开销小、不影响业务库性能,是现在实时数仓 ODS 层标准入仓方案。

八、常用工具

  • Flink CDC:目前主流,直接对接 Flink,不用中间 Canal
  • Canal:阿里开源,经典老方案
  • Debezium:开源标准,生态通用

实时数仓完整分层架构 + CDC 面试常问 5 题(可直接背)

一、实时数仓标准四层架构(面试必说)

1. ODS 原始数据层

  • 来源:MySQL Binlog + 业务日志
  • 接入方式:Flink CDC / Canal 监听 Binlog,实时推到 Kafka ODS 主题
  • 特点:原样保存原始变更,全量 + 增量,不做清洗
  • 作用:数据入仓入口,留存原始流水

2. DWD 明细宽表层

  • 引擎:Flink 消费 Kafka ODS
  • 做:清洗、过滤、脱敏、字段规整、维度关联
  • 输出:干净业务明细,写入 Kafka DWD 主题
  • 特点:大宽表化,后续不用再关联维表

3. DWS 聚合中间层

  • 引擎:Flink 窗口聚合、分组统计、UV、交易额等指标
  • 做:按时间、区域、渠道、用户聚合中间指标
  • 输出:写入 Kafka / Doris / ClickHouse

4. ADS 应用指标层

  • 存储:Apache Doris / ClickHouse
  • 用途:实时大屏、BI 报表、业务查询、对外接口
  • 特点:预聚合完成,直接对外提供服务

二、实时数仓标准数据流链路

MySQL → Flink CDC → Kafka (ODS) → Flink 清洗加工 (DWD) → Kafka (DWD) → Flink 聚合 (DWS) → Doris/ClickHouse(ADS)


三、CDC 面试常问 5 题(标准答案)

1. 什么是 CDC?

CDC 是变更数据捕获,实时监听数据库 Binlog,抓取 Insert/Update/Delete 增量变更,不用全量拉表,低延迟、无侵入同步数据。

2. CDC 有几种实现方式?

三种:

  1. 定时轮询:按时间戳查增量,有延迟、压力大
  2. 数据库触发器:侵入业务库,影响性能,生产不用
  3. Binlog 监听:Flink CDC/Canal/Debezium,生产主流,无侵入、秒级延迟
  • Canal:独立中间件,部署重,需要维护一套服务
  • Flink CDC:直接集成在 Flink 任务里,无需中间组件,开发运维简单,支持全量 + 增量自动同步,现在实时数仓首选。

4. CDC 同步能解决什么问题?

  • 替代传统定时全量同步,节省资源
  • 秒级实时入仓,支撑大屏实时指标
  • 只同步增量,流量、计算开销小
  • 对 MySQL 业务无性能侵入
  • 可完整捕获删改增所有操作

5. CDC 同步怎么处理历史全量 + 增量?

Flink CDC 支持先全量快照、再自动切增量

先一次性拉取表全量初始化,再无缝监听后续 Binlog 增量,一条任务搞定全量 + 增量,不用分开开发。


四、面试 30 秒口述整套架构

我们实时数仓采用四层架构:ODS 层通过 Flink CDC 监听 MySQL Binlog,实时采集增量变更写入 Kafka;DWD 层用 Flink 做清洗、脱敏和维度关联生成明细宽表;DWS 层做窗口聚合计算中间指标;最后落地到 Doris 做 ADS 应用层,支撑实时大屏和 BI 报表。

整体用 CDC 增量同步替代传统全量抽取,秒级延迟、节省资源、不影响业务库,是目前实时数仓标准入仓方案。

待丰富问题

  1. 如何保证数据不重不漏

大数据开发

大数据面试核心全家桶「一页纸背诵版」

涵盖:Kafka、Flink、Spark、Doris、ClickHouse,精简到只背核心,面试直接脱口而出。


一、Kafka 核心速记

核心组件

生产者、Broker、Topic、Partition 分区、副本、消费者组、Offset 偏移量。

关键原理

  1. 分区:单分区有序、全局无序;分区决定并行度。
  2. 副本:Leader 读写,Follower 同步,高可用。
  3. ACK:0 最快易丢;1 落 Leader;-1/all 最安全。
  4. 削峰填谷:磁盘可堆积,高峰缓存、低峰匀速消费,解耦护下游。

常见问题 & 解决

  • 消息丢失:acks=-1 + 多副本 + 先消费后提交 offset
  • 重复消费:业务唯一主键幂等、手动提交 offset
  • 重平衡频繁:调大会话超时、稳定消费者数量
  • 数据积压:加分区、加消费并行度、优化消费逻辑

调优口诀

生产者开批量 + 压缩 + acks=-1;

消费者关自动提交、批量拉取;

分区与 Flink/Spark 并行度对齐;生产 3 副本。


核心特性

原生流式、EventTime+Watermark 水位线、窗口、Checkpoint + 状态、Exactly-Once。

关键概念

  1. 时间语义:事件时间、处理时间、摄入时间。
  2. 水位线:处理乱序 / 迟到数据,触发窗口计算。
  3. Checkpoint:保存偏移量 + 状态,故障自动恢复。
  4. 状态后端:生产必用 RocksDB,配 TTL 防膨胀 OOM。

项目难点

数据倾斜、任务反压、窗口不触发、状态 OOM、重复消费、落库小文件。

解决口诀

倾斜:预聚合 + 热点 key 加盐打散;

反压:定位瓶颈算子、加并行度;

状态:RocksDB + 增量 CK+TTL 过期清理;

迟到:水位线 + 允许迟到 + 侧输出兜底。


三、Spark 核心速记

核心原理

RDD 惰性求值、DAG 宽窄依赖、遇到 Shuffle 切分 Stage、Task 分区执行。

版本区别

  1. Spark Streaming:老旧固定微批,已淘汰。
  2. Spark Structured Streaming:默认微批,不是事件驱动,适合准实时。

核心短板

事件时间、水位线、乱序处理、长期状态远不如 Flink。

常见问题 & 调优

  • 数据倾斜:空值过滤、加盐打散、两阶段聚合
  • OOM:Driver 别 collect、合理分区、加大内存
  • 小文件:repartition/coalesce 合并、离线定时合并
  • 优化口诀:尽早过滤、谓词下推、广播 Join、少 Shuffle、合理缓存。

  • 离线数仓、批量 ETL、报表画像 → 选 Spark
  • 实时大屏、低延迟、乱序日志、窗口精准、Exactly-Once → 选 Flink
  • 流批一体架构 → 全站 Flink,离线保留 Spark

五、Doris vs ClickHouse 全方位速记

ClickHouse

单表查询极致快、压缩率高;Join 弱、更新差、并发低、运维重;适合日志、时序、离线大宽表,不复杂关联。

Apache Doris

全能 OLAP;CBO 优化器、多表 Join 强、支持 UPSERT/DELETE 实时更新、兼容 MySQL、运维简单、高并发 BI、湖仓一体友好。

选型口诀

复杂关联、实时更新、高并发 BI、运维简单、湖仓一体 → Doris

纯日志时序、单表大宽表、几乎不更新、追求极致查询性能 → ClickHouse


六、大数据常用 SQL 分清

  1. Hive SQL:传统离线数仓标配
  2. Spark SQL:当下主流高性能大数据 SQL
  3. Flink SQL:实时流处理专用 SQL
  4. Presto/Trino:跨数据源统一查询
  5. T-SQL:SQL Server、Azure Synapse 微软数仓
  6. Cosmos DB SQL:Cosmos 自研类 SQL,查 JSON 文档,不是 T-SQL