跳到主要内容

数据迁移问题排查

场景描述

公司要将数仓从 Hive 迁移到 ClickHouse,迁移后发现部分指标数据对不上。

迁移常见问题

问题原因排查方法
数据量不一致迁移丢数 / 过滤条件差异COUNT 对比
数值不一致类型精度丢失 / 空值处理差异SUM 对比 + 抽样检查
时区不一致源和目标时区设置不同检查同一条记录的时间字段
字符编码问题UTF-8 vs GBK检查中文/特殊字符
增量遗漏CDC 有延迟检查最大 ID / 最大时间戳

数据校验步骤

1. 总量校验

-- 源端(Hive)
SELECT dt, COUNT(*) AS cnt, SUM(amount) AS total_amount
FROM hive_db.order_fact
WHERE dt = '2024-01-15'
GROUP BY dt;

-- 目标端(ClickHouse)
SELECT dt, COUNT(*) AS cnt, SUM(amount) AS total_amount
FROM ck_db.order_fact
WHERE dt = '2024-01-15'
GROUP BY dt;

-- 对比结果:cnt 和 total_amount 应完全一致

2. 抽样校验

-- 随机抽取 1000 条记录对比
SELECT order_id, user_id, amount, created_at
FROM hive_db.order_fact
WHERE dt = '2024-01-15'
ORDER BY RAND()
LIMIT 1000;

-- 在目标端逐条核对

3. 维度交叉校验

-- 按关键维度聚合对比
SELECT dt, channel, city,
COUNT(*) AS cnt,
SUM(amount) AS total_amount
FROM order_fact
WHERE dt = '2024-01-15'
GROUP BY dt, channel, city;

自动化校验脚本

import pandas as pd

def data_validation(source_df, target_df, pk_cols, check_cols):
"""数据迁移校验"""
report = {}

# 1. 行数对比
report['source_count'] = len(source_df)
report['target_count'] = len(target_df)
report['count_match'] = report['source_count'] == report['target_count']

# 2. 数值列聚合对比
for col in check_cols:
s_sum = source_df[col].sum()
t_sum = target_df[col].sum()
diff_pct = abs(s_sum - t_sum) / s_sum * 100 if s_sum != 0 else 0
report[f'{col}_diff_pct'] = f'{diff_pct:.4f}%'

# 3. 主键重叠检查
source_pk = set(source_df[pk_cols].apply(tuple, axis=1))
target_pk = set(target_df[pk_cols].apply(tuple, axis=1))
report['missing_in_target'] = len(source_pk - target_pk)
report['extra_in_target'] = len(target_pk - source_pk)

return report

常见面试问题

Q1: 数仓迁移如何做到零停机?

答案

双写 + 灰度切换

  1. 双写阶段:新旧数仓同时写入,保持一致
  2. 校验阶段:每日对比新旧数仓数据,确保一致
  3. 灰度切换:先切读流量(BI 报表),确认无误后再切全量
  4. 回退方案:切换后保留旧数仓 1-2 周,随时可回退

Q2: 迁移后数值有微小差异(0.01%)是否可接受?

答案

需要分析差异原因:

  • 浮点精度:Hive DOUBLE vs ClickHouse Float64,可能有精度丢失 → 可接受,但建议用 DECIMAL
  • 空值处理:Hive 的 NULL + 10 = NULL vs ClickHouse 可能 = 10 → 不可接受,需统一
  • 时区差异:跨天的订单归属日期不同 → 不可接受,需统一

结论:精度引起的微小差异可接受;逻辑差异不可接受。


相关链接