同一份数据在源表有、在 Hologres 查出来对不上,先不要把它直接归因成写入延迟。判断方向通常是两条:查询用的时间窗口和分区条件是否把目标数据排除了;写入链路从提交到可查询之间是否还没走完。源表如果还在持续写入,比较也会一直漂移,所以先把比较时刻、批次标识和查询 SQL 固定下来。
缺行优先核对查询条件是否指定了正确的分区或时间窗口,再记录写入时刻到可查询的间隔;如果时间窗口正确、间隔已超过链路正常可见时间,仍缺行,就按业务唯一键做交集和差集,判断是缺行还是同一行取值不一致。不要用一次查询结果下结论,源表持续写入时先冻结比较时间点;无法复现时保留 SQL、分区条件和查询时刻再排查。
先确认查询用的是哪个时间窗口和分区条件
适用场景:Hologres 表按 ds、hour 或业务日期分区,查询条件里只写了业务键或状态,没有写分区键。操作动作:对同一业务键,显式指定预期分区和不指定分区各跑一次 count,记录两次返回条数。验证方式:如果显式分区查得到、不指定分区查不到,优先检查客户端默认时间范围、视图过滤、时区转换和分区键类型是否匹配。风险边界:不带分区条件查大表可能扫很多子表,只适合在明确有分区裁剪或小范围条件时使用,不要在生产高峰反复执行。
-- A:显式指定你预期数据所在的分区
select count(*) as cnt_part
from dwd_order
where ds = '2025-01-01'
and hour = '10'
and order_id = 'O10001';
-- B:去掉分区条件,只按业务键查
select count(*) as cnt_all
from dwd_order
where order_id = 'O10001';
-- C:查询该表分区元信息,按当前实例支持的方式
-- 例如通过表管理页面、information_schema 或分区管理 SQL 确认 ds/hour 范围
把两次结果填入下表,差异本身比结论有用:
| 查询编号 | 分区/时间条件 | 返回条数 | 与显式分区查询的差异 | 备注 |
|---|---|---|---|---|
| A | ds=2025-01-01, hour=10 | 基准 | 确认分区键值来自写入任务 | |
| B | 无分区条件 | 若 B 少于 A,查默认过滤或权限视图 | ||
| C | 分区元信息 | 确认目标分区是否已存在 |
如果 A 和 B 都为 0,说明目标行在查询可见范围内不存在,继续做写入时刻记录和唯一键比对;如果 A 有、B 没有,先解决查询条件和分区裁剪问题,不要先查写入链路。
记录写入时刻到可查询之间的间隔
适用场景:实时写入、Flink/DataWorks 导入、外表导入或批量任务刚提交,源表已能查到,Hologres 暂时查不到。操作动作:写入方在提交时记录批次标识和写入时刻,查询方在 T0、T1、T2 等时间点用同一 SQL 重复取数,形成时间与条数的变化表。验证方式:如果同一批次 count 随时间增加,通常是可见延迟;如果超过该链路正常可见时间仍为 0,再查导入任务日志、事务提交状态和分区是否写到了预期分区。风险边界:不要因为一次 count 为 0 就判断丢数,也不要把查询缓存、连接会话状态和任务排队混在一起判断。
-- 写入方记录:batch_id、write_ts、预期行数
-- 查询方按时间点重复执行
select count(*) as cnt
from dwd_order
where batch_id = 'B20250101_001'
and ds = '2025-01-01'
and hour = '10';
| 批次标识 | 源表写入完成时刻 | 查询时刻 | 返回条数 | 相对预期 | 备注 |
|---|---|---|---|---|---|
| B20250101_001 | T_write | T0 | 第一次查询 | ||
| B20250101_001 | T_write | T1 | T1 晚于 T0 | ||
| B20250101_001 | T_write | T2 | 观察是否收敛到预期 |
这张表只记录时间、批次和条数,不写“延迟几秒”的结论。若条数在 T0 到 T2 增加并稳定,按延迟处理;若一直为 0 或稳定少于预期,进入唯一键差集比对。
按唯一键核对两边是否对得上
适用场景:时间窗口和分区都正确,批次也过了可见时间,但总数仍对不上。操作动作:按业务唯一键在源表侧和 Hologres 侧各取一份键集合,做交集和差集。验证方式:差集结果中只有源表有键,说明 Hologres 缺行;只有 Hologres 有键,说明可能重复写入或源表已删除未同步;两边都有键但金额、状态不同,说明是同行取值不一致。风险边界:源表如果还在更新,先固定 update_time 或快照时间,否则差集会把正常更新误判成缺失。
-- 若源表可作为外部表或联邦查询访问,用 full join 看三类结果
with src as (
select order_id, amount, update_time
from source_order
where ds = '2025-01-01'
),
hol as (
select order_id, amount, update_time
from dwd_order
where ds = '2025-01-01' and hour = '10'
)
select
coalesce(s.order_id, h.order_id) as order_id,
case
when s.order_id is null then 'hol_only'
when h.order_id is null then 'src_only'
else 'both_diff'
end as diff_type,
s.amount as src_amount,
h.amount as hol_amount,
s.update_time as src_update_time,
h.update_time as hol_update_time
from src s
full join hol h on s.order_id = h.order_id
where s.order_id is null
or h.order_id is null
or s.amount != h.amount;
如果源表不能直接在 Hologres 里查询,就把两边的 order_id 和 update_time 分别导出到临时表或本地文件,再用同样的 full join 逻辑比对。差集结果的使用方式:src_only 且 update_time 很新,优先看写入延迟;src_only 且 update_time 较早,查同步任务、过滤条件和分区落点;hol_only 查重复写入或删除同步;both_diff 查字段映射、更新顺序和聚合逻辑。
逐条注释查询条件再跑一次
适用场景:你怀疑查询 SQL 里有隐式过滤、NULL 比较、时区转换或视图默认条件。操作动作:从原始查询开始,每去掉一个 where 条件就跑一次 count,记录返回条数变化。验证方式:去掉某个条件后条数明显增加,说明该条件在过滤;去掉后条数不变,说明该条件对当前数据没有筛除作用。风险边界:不要用 select * 全表拉生产大表,用 count 加分区条件逐步收窄。
-- 原始查询
select count(*) from dwd_order
where ds = '2025-01-01'
and hour = '10'
and status = 'paid'
and is_deleted = false;
-- 去掉 status
select count(*) from dwd_order
where ds = '2025-01-01'
and hour = '10'
and is_deleted = false;
-- 去掉 is_deleted
select count(*) from dwd_order
where ds = '2025-01-01'
and hour = '10';
-- 只保留分区
select count(*) from dwd_order
where ds = '2025-01-01';
| 步骤 | 保留条件 | 去掉条件 | 返回条数 | 与原始差值 | 观察线索 |
|---|---|---|---|---|---|
| 原始 | ds,hour,status,is_deleted | 无 | 基准 | 记录 SQL 原文 | |
| 1 | ds,hour,is_deleted | status | status 是否过滤了目标行 | ||
| 2 | ds,hour | is_deleted | NULL 或默认值是否被隐藏 | ||
| 3 | ds | hour | 目标行是否落在别的 hour |
同时检查日期字符串是否经过时区转换、分区键是否发生隐式类型转换、视图或行级权限是否自动追加了条件。这些都可以通过对比去掉条件后的条数和查看视图定义来验证。
给出可复现的排查顺序
下次遇到同类现象,按可观察现象走,不按猜测走。下表只写现象、先查哪项和判定标准,判定标准以你实际看到的返回条数、日志和分区元信息为准。
| 现象 | 先查哪项 | 判定标准 |
|---|---|---|
| 显式分区条件查得到,不指定分区查不到 | 查询的分区条件和时间窗口 | 两次 SQL 返回条数不同;记录分区键值和客户端默认时间范围 |
| 同一批次刚写入查不到,过一段时间能查到 | 写入时刻到可查询的间隔 | 按 T0/T1/T2 重复 count,条数增加并收敛;否则查导入任务日志 |
| 时间窗口正确、批次已过可见时间,源表有、Hologres 无 | 按唯一键做差集 | 差集中出现 src_only 行;再看这些行是否落在目标分区 |
| 两边唯一键都在,但金额或状态不同 | 更新时间和字段映射 | 按 update_time 排序看最后一条;查同步任务是否漏字段或乱序 |
| 去掉某个 where 条件后条数变化 | 被去掉的过滤条件 | 该条件是否业务预期;检查 NULL、时区、类型转换、视图默认过滤 |
| Hologres 侧出现源表没有的键 | 重复写入或源表删除同步 | 查同键多行、任务主键和删除标记是否同步 |
把每次查询的 SQL、分区条件、查询时刻、批次标识和返回条数留下来,再按上面的顺序逐项排除。没有这些记录,写入延迟和查询走错分区很容易反复争执,也很难复现。