SQL 分布式与大数据 SQL

2次阅读

sql分布式系统中查不准,因多数引擎不保证跨节点事务一致性,select可能读取不同时间点快照;各引擎NULL处理、类型转换、时区、精度规则不一;批流语义差异及shuffle、分区、窗口等机制影响结果与性能。

SQL 分布式与大数据 SQL

SQL 在分布式系统里为什么总查不准

因为大多数 SQL 引擎默认不保证跨节点事务一致性,SELECT 看到的数据可能是不同时间点的快照。比如用 clickhouse 查分片表,没加 FINAL 或没配 replicated_merge_tree,就可能读到未合并的旧版本数据;Trino 连多个异构源时,count(*) 本身不走事务,各数据源返回的行数直接相加,但某源正在写入中,结果就偏高。

  • 查前先确认执行引擎是否支持强一致读——StarRocksquery_timeoutenable_global_dict 会影响结果可见性
  • 避免在 WHERE 中用非分区键字段做高选择性过滤,分布式下容易触发全节点扫描,响应延迟突增
  • mysql 分库分表(如 ShardingSphere)中,ORDER BY + LIMIT 必须带 sharding key,否则聚合排序结果错误

大数据场景下 SQL 跑得慢,90% 是没避开 shuffle

spark SQL 或 flink SQL 里,JOINGROUP BYWINDOW 都会触发 shuffle,而 shuffle 是磁盘+网络密集型操作。尤其当小表没广播、大表没提前过滤时,shuffle 数据量爆炸。

  • BROADCAST JOIN 前确认小表真实大小——spark.sql.autoBroadcastJoinThreshold 默认 10MB,但压缩后体积 ≠ 内存展开后体积
  • GROUP BY 字段尽量选高基数列,避免倾斜;若必须按低基数字段分组(如 status),加 SALT 扰动或改用 partial_agg + final_agg 两阶段
  • Flink 中 OVER WINDOW 若基于 PROCTIME,不触发 shuffle;但换成 ROWTIME 就要等 watermark,延迟不可控

同一份 SQL,在 hive/Trino/StarRocks 上结果不同

不是语法错了,是 NULL 处理、类型隐式转换、时区、精度截断规则不一致。比如 HiveCAST('2023-01-01' AS timestamp) 默认按系统时区解析,Trino 默认 UTC,StarRocks 则依赖 session 变量 time_zone

  • NULL = NULLHive 返回 NULLStarRocks 返回 FALSE,写 WHERE col1 = col2 时逻辑完全不同
  • DECIMAL 计算:Hive 用 ROUND_HALF_UP,Trino 用 HALF_EVEN,同一条 SUM(ROUND(x, 2)) 可能差一分钱
  • 分区字段类型别混用——Hive 分区是 StringTrino 对应表定义成 dateWHERE ds = '2023-01-01' 会静默跳过所有分区

想用 SQL 做实时流处理,但结果总滞后或重复

核心矛盾在于:传统 SQL 是批语义,而流式 SQL 必须显式声明时间属性和状态清理策略。Flink SQL 默认用 Event TIME,但如果你的 kafka 消息没带 timestamp 字段,或 WATERMARK 设置太激进,就会丢数据或乱序。

  • WATERMARK for ts AS ts - INTERVAL '5' SECOND 中的 '5' 不是固定值,得根据上游最大乱序延迟反推,不能拍脑袋设
  • INSERT INTO sink SELECT ... FROM source GROUP BY TUMBLING(HOP)... 里,HOP 窗口必须指定 offset,否则凌晨零点切窗可能漏掉跨天数据
  • 更新类 sink(如 StarRocksDoris)需开启 ON DUPLICATE KEY UPDATE 语义,否则 UPSERT 流会变成追加,主键冲突直接报错

分布式 SQL 最难的不是写出来,而是搞清每条语句背后实际跑在哪几个节点、数据怎么分发、状态怎么同步、时间怎么对齐。这些细节不抠清楚,换引擎、调参数都只是隔靴搔痒。

text=ZqhQzanResources