left join配合where右表主键is null是最可靠增量提取方式,因其基于主键物理比对识别“源表有、目标表无”的记录,不依赖时间戳或版本号;必须用is null而非= null,且需确保右表关联字段有索引、null值场景需显式处理。

LEFT JOIN 配合 WHERE 右表主键 IS NULL 是最直接、最可靠的增量提取方式,不依赖时间戳,避免因字段缺失或不准导致漏数据。
为什么用 LEFT JOIN + IS NULL 而不是 WHERE = NULL
增量的本质是「源表有、目标表无」。LEFT JOIN 保留左表(源)全部记录,右表(目标)没匹配上的字段全为 NULL;再用 WHERE t.id IS NULL 就能精准筛出这些缺失行。
常见错误是写成 = NULL —— SQL 中任何值与 NULL 比较都返回 UNKNOWN,结果永远为空。必须用 IS NULL。
- 漏写
WHERE t.id IS NULL→ 返回源表全量,误以为是增量 - 右表关联字段没索引 → 即使加了
IS NULL,优化器仍可能全表扫描,性能骤降 - 复合主键场景下,
ON条件必须覆盖全部主键字段,例如:s.order_id = t.order_id AND s.sku_code = t.sku_code
NULL 值字段导致匹配失败怎么办
当关联字段(如 email)允许 NULL 时,ON s.email = t.email 会跳过所有含 NULL 的行——因为 NULL = NULL 返回 UNKNOWN,不算匹配成功。
正确写法是显式补全 NULL 匹配逻辑:
SELECT s.* FROM source_user s LEFT JOIN target_user t ON (s.email = t.email OR (s.email IS NULL AND t.email IS NULL)) WHERE t.email IS NULL;
注意:不能只写 OR (s.email IS NULL AND t.email IS NULL),否则破坏等值前提,可能引发笛卡尔积。
- 多个可能为
NULL的字段(如phone、address)需逐个展开判断,SQL 迅速变长 - 此时建议改用
NOT EXISTS,语义更清晰,也更容易维护 - PostgreSQL 用户可用
s.email IS NOT DISTINCT FROM t.email简化写法
多表 JOIN 后怎么安全做增量导出
不能在最终 JOIN 结果上直接 WHERE updated_at > ?——这会漏掉「关联表更新但主表未动」的业务记录。
真正要捕获的是「任一相关表自上次导出后发生变更」的完整业务行,所以得先算出逻辑最新时间:
SELECT s.*, GREATEST( COALESCE(t1.updated_at, '1970-01-01'), COALESCE(t2.updated_at, '1970-01-01') ) AS last_updated FROM source s LEFT JOIN table1 t1 ON s.id = t1.source_id LEFT JOIN table2 t2 ON s.id = t2.source_id WHERE GREATEST( COALESCE(t1.updated_at, '1970-01-01'), COALESCE(t2.updated_at, '1970-01-01') ) > '2026-06-20';
-
GREATEST()在 MySQL 5.7+ 支持,PostgreSQL 需绕写(如用VALUES或窗口函数) -
COALESCE必须兜底,否则任意一个updated_at为NULL就让整行GREATEST返回NULL - 性能关键:把时间过滤下推到子查询,比如先
WHERE updated_at > ?分别筛table1和table2,再JOIN,比全量JOIN后筛快得多
为什么 RIGHT JOIN 几乎不用,LEFT JOIN 更好控制
实际执行中,RIGHT JOIN 和 LEFT JOIN 逻辑等价,但可读性差——谁是驱动表、谁是被驱动表,一眼看不出。绝大多数人习惯从左往右读,所以统一用 LEFT JOIN,把主表放左边,辅表放右边,意图明确。
更重要的是,优化器对 LEFT JOIN 的驱动表选择更稳定;而 RIGHT JOIN 容易让开发误以为右表是主表,结果在写 WHERE 条件时错加在右表字段上,导致逻辑错误。
- 如果业务天然以右表为主(比如按订单状态查用户),直接调换表顺序写成
FROM target_user t LEFT JOIN source_user s ON ...,比硬用RIGHT JOIN清晰 - MySQL 默认使用
Index Nested-Loop Join,左表是否走索引、右表关联字段有没有索引,直接影响性能,LEFT JOIN更利于人工干预驱动表选择
真正容易被忽略的是右表的统计信息和索引状态——哪怕 SQL 写得完全正确,只要 target 表的关联字段没索引,或者 ANALYZE TABLE 长期没跑,优化器就可能选错执行计划,把 IS NULL 过滤拖成全表扫描。上线前务必确认这两点。











