on中必须用and连接多条件,因标准sql不支持逗号分隔或元组比较语法;逗号写法直接报错,(a,b)=(c,d)仅部分引擎支持且无法走索引;漏写and或顺序错会导致语法错误、隐式转换或索引失效。

ON里写多个AND条件,为什么不能用逗号或括号
因为标准 SQL 不支持 (a, b) = (c, d) 或 ON a = c, b = d 这类写法——前者是 PostgreSQL 的 ROW 比较语法(且不适用于所有 JOIN 场景),后者在 MySQL/SQL Server/PostgreSQL 中直接报语法错误。
必须显式写出每个等值关系,用 AND 连接。例如:
SELECT * FROM orders o JOIN users u ON o.user_id = u.id AND o.tenant_id = u.tenant_id
-
ON o.user_id = u.id, o.tenant_id = u.tenant_id→ 语法错误 -
ON (o.user_id, o.tenant_id) = (u.id, u.tenant_id)→ 仅部分引擎支持,且无法走索引 - 漏掉任一
=(如写成ON o.user_id = u.id AND o.tenant_id u.tenant_id)→ 语法错误或隐式转换风险
LEFT JOIN 里把过滤条件放 WHERE 还是 ON,差别在哪
差别直接决定左表行是否保留。比如想查所有订单及其「已激活」的用户信息,但又不想丢掉没匹配到用户的订单:
✅ 正确(保左表):LEFT JOIN users u ON o.user_id = u.id AND u.status = 'active'
❌ 错误(丢左表):LEFT JOIN users u ON o.user_id = u.id WHERE u.status = 'active'
后者实际等价于 INNER JOIN,因为 WHERE u.status = 'active' 会筛掉 u.status 为 NULL 的行——也就是所有没匹配上用户的订单全被干掉了。
- 只要右表字段出现在
WHERE,就可能让LEFT JOIN失效 -
ON中的AND是关联逻辑的一部分;WHERE是关联完成后的全局过滤 - 哪怕只是
WHERE u.id IS NOT NULL,也会导致左表空匹配行被剔除
多列 JOIN 时索引为啥没生效
不是建了两个单列索引就行。优化器通常只选其一,另一列靠扫描过滤,key_len(MySQL)或 Index Cond(PostgreSQL)能暴露问题。
必须建联合索引,且顺序尽量和 ON 中字段顺序一致。例如:
CREATE INDEX idx_orders_user_tenant ON orders(user_id, tenant_id);
对应 ON o.user_id = u.id AND o.tenant_id = u.tenant_id 才能两列都走索引查找。
- 如果
ON是tenant_id在前,但索引是(user_id, tenant_id)→ 只能用上第一列 -
ON UPPER(a.code) = UPPER(b.code)→ 函数操作导致索引失效 - 范围条件(
>、BETWEEN)后出现的等值列,大概率无法用于索引查找
AND 和 OR 混在 ON 里,为什么容易翻车
AND 安全,OR 危险——不是语法错,而是执行计划和语义双崩。
比如:JOIN customers c ON c.id = o.customer_id OR c.is_default = 1,会导致:
- 单条订单可能匹配多条客户(
is_default = 1全局成立,无绑定约束) - 优化器大概率放弃索引,走全表扫描
- 结果行数爆炸,内存/IO 压力陡增
真需要多路径关联,优先拆解:
- 两个
LEFT JOIN+COALESCE(c1.name, c2.name) -
UNION ALL两个独立JOIN结果(注意字段类型对齐) - 把
OR条件移到WHERE—— 但仅限你接受“先连后筛”的开销
最常被忽略的点:JOIN 条件不是布尔练习题,而是数据关系建模。写 OR 前先问一句——这两个条件,真的定义的是同一种业务关联吗?











