1. 统一SQL概述:为什么需要统一SQL?

做数据开发的朋友,十有八九都遇到过这个场景:

业务方早上跑来问:「昨天的DAU是多少?」
你查离线数仓,回答「1250万」。
旁边实时团队说「不对,我们实时看的是1280万」。

两边数字对不上。业务方懵了,你更懵。

这种「口径差异」我见过太多次了。刚入行那几年,我甚至觉得这是常态——离线归离线,实时归实时,各算各的呗。直到有一次大促复盘,离线口径和实时口径差了将近5%,老板在会上直接问「到底哪个是对的?」

嗯,从那以后我就开始认真琢磨:能不能用一套SQL,把实时和离线统一起来?

1.1 实时与离线口径差异的根源

要解决差异,先得搞清楚差异从哪来。我把它归结为三个层面:

1.1.1 数据源差异

离线任务读的是Hive表、HDFS文件,数据是T+1的,已经落盘了。
实时任务读的是Kafka、Pulsar这类消息队列,数据是流式的,还没定型。

你想想看,一个是从仓库里拿冻货,一个是从流水线上抓活鱼。源头就不一样,算出来的结果能完全一致吗?

维度 离线数据源 实时数据源
存储介质 Hive / HDFS / HBase Kafka / Pulsar / Redis
数据状态 已落盘、不可变 未落盘、持续流入
回溯能力 强(全量重跑) 弱(依赖offset重置)
数据质量 可清洗、可回溯 可能有乱序、延迟
我的经验: 离线数据源虽然「干净」,但时效性差。实时数据源虽然「新鲜」,但经常有迟到数据。统一SQL的第一步,就是让这两种数据源在语义层对齐。

1.1.2 计算引擎差异

离线计算,大家用的多是Hive、Spark SQL、Presto。这些引擎擅长批处理,吞吐量大,延迟高一点没关系。

实时计算,主流是Flink SQL、Spark Streaming。它们处理的是无界流,要求低延迟、高吞吐,但状态管理复杂。

我遇到过最头疼的事:同一个SUM聚合,在Hive里跑出来是100,在Flink里跑出来是99.8。查了半天,发现是Flink的浮点累加顺序不同导致的精度损失。

说白了,引擎底层的计算模型、状态管理、容错机制都不一样。你指望它们天然对齐?不现实。

对比项 离线引擎(Hive/Spark) 实时引擎(Flink)
计算模型 批处理(有界数据) 流处理(无界数据)
容错机制 任务重跑 Checkpoint + 状态恢复
精度控制 精确一次(易实现) 精确一次(需配置)
典型延迟 分钟~小时级 秒~分钟级

1.1.3 时间语义差异

这是最隐蔽、也最容易踩坑的地方。

离线任务通常用处理时间——也就是任务跑起来的那一刻。比如每天凌晨2点跑昨天的数据,那「昨天」就是固定的分区。

实时任务则更关注事件时间——也就是用户行为实际发生的时间。但问题来了:用户的行为日志可能延迟到达,比如网络不好、手机离线,事件时间戳可能是10分钟前的。

我记得有一次做实时大屏,PV数据总是比离线少3%左右。排查后发现,实时任务用了事件时间,但watermark设置得太激进,把一些迟到数据丢掉了。离线任务用的是处理时间,所有数据都算进去了。

你看,同一个指标,同一个SQL逻辑,就因为时间语义不同,结果就不一样。

避坑指南: 我曾经因为时间语义没对齐,导致实时报表和离线报表差了整整一个周末的数据量。后来我们统一约定:实时任务也保留处理时间字段,用于和离线做交叉验证。这个习惯我一直保持到现在。

1.2 统一SQL的核心思路

既然差异的根源清楚了,那怎么解决?

我的答案是:构建一套SQL抽象层,让同一段SQL在实时和离线引擎上跑出相同的结果。

这不是让Flink和Hive变得一样,而是让它们对外暴露的SQL语义一致。具体来说:

  • 语法统一:同一段SELECT、JOIN、AGGREGATE,在离线和实时引擎上都能解析执行。
  • 语义统一:时间窗口、去重逻辑、状态管理,在两种引擎下行为一致。
  • 结果统一:相同输入,相同逻辑,输出相同结果。

你可能会问:这能做到吗?

能。但需要一些「技巧」。比如:

  • 用统一的元数据层屏蔽数据源差异
  • 用标准化的时间函数处理时间语义
  • 用Lambda架构或Kappa架构做结果校验

这些内容,后面的章节会一个一个展开讲。

1.3 统一SQL的价值

说点实际的。统一SQL能带来什么好处?

  1. 减少沟通成本:实时团队和离线团队不用再为「谁的数字对」吵架。
  2. 提升开发效率:写一套SQL,到处运行。不用维护两套逻辑。
  3. 保证数据一致性:业务方看到的是一个数字,而不是两个。
  4. 降低运维复杂度:口径变更只需改一处,实时和离线同步生效。

一句话总结: 统一SQL不是技术炫技,而是解决实际业务痛点的工程手段。它让数据团队从「救火」变成「预防」,从「解释差异」变成「消除差异」。

1.4 本章知识体系

下面这张图,帮你快速理清本章的核心脉络:

统一SQL知识体系图 统一SQL知识体系 统一SQL 数据源差异 计算引擎差异 时间语义差异 统一元数据层 标准化SQL函数 Lambda/Kappa架构 实时与离线口径一致 核心思路:用一套SQL抽象层,屏蔽底层差异,保证实时与离线计算结果一致

这张图把本章的核心逻辑串起来了。从左到右看:先搞清楚差异从哪来,再针对性地给出解决方案,最终实现口径统一。

后面的课程,我会带着你一步步把这些方案落地。包括怎么写统一SQL、怎么配置元数据、怎么处理迟到数据、怎么做结果校验……都是我在实际项目中踩过坑、填过坑之后总结出来的经验。

准备好了吗?我们开始。