最通用方案是在join的on条件中对两边字段同时使用upper()或lower()函数;若右表字段有索引且查询高频,优先调整collate而非加函数;必须避免仅转换一边导致匹配遗漏。

直接在 JOIN 条件里用 UPPER() 或 LOWER() 两边同时转换,是最通用、最可控的方案;但若右表字段已有索引且查询高频,优先改 COLLATE 而非加函数。
ON 条件里必须两边都用 UPPER(),不能只转一边
只写 ON t1.name = UPPER(t2.customer_name) 会漏掉 t1.name 是小写的记录,因为比较仍按原始大小写进行。真正起作用的是两端统一形态:
-
ON UPPER(t1.name) = UPPER(t2.customer_name)—— 安全、跨库兼容 - 若字段可能为
NULL,UPPER()本身返回NULL,不会报错,但会导致该行无法匹配(符合预期) - 若字段含全角空格或不可见字符,得先
TRIM()再UPPER():例如ON UPPER(TRIM(t1.name)) = UPPER(TRIM(t2.customer_name))
别在 WHERE 里用 UPPER() 做关联过滤
WHERE UPPER(t1.name) = 'ALICE' 看似能查到所有变体,但它会让 t1.name 上的索引完全失效——优化器无法下推索引查找,只能全表扫描。
- 正确做法是把大小写归一化逻辑严格限制在
ON子句中,仅用于连接对齐 - 如果真要查“叫 Alice 的用户”,且
name字段有索引,应确保该列COLLATE是不区分大小写的(如utf8mb4_0900_as_cs不行,utf8mb4_0900_ai_ci可以) - SQL Server 可临时指定:
WHERE t1.name COLLATE SQL_Latin1_General_CP1_CI_AS = 'Alice',部分版本能走索引
PostgreSQL 用 ILIKE 更简洁,但不能替代函数索引
PostgreSQL 不支持在 WHERE 或 ON 中用 COLLATE 切换排序规则做等值比较,所以 ILIKE 是原生替代方案:
-
ON u.name ILIKE p.owner_name语义清晰,比UPPER()少一层函数调用 - 但它和
UPPER()一样,无法利用name列上的普通 B-Tree 索引 - 想提速?建表达式索引:
CREATE INDEX idx_lower_owner ON projects (LOWER(owner_name));,然后改用ON LOWER(u.name) = LOWER(p.owner_name) -
ILIKE支持通配符,但别混用:ON u.name ILIKE 'A%' AND u.status = 'active'可能导致索引选择失衡
真正麻烦的是跨库或混合 collation 场景
当左表来自 MySQL(utf8mb4_0900_as_cs),右表来自 PostgreSQL(默认区分大小写),或者两个表同一库但 COLLATE 不同,COLLATE 方案就失效了——这时 UPPER() 是唯一不依赖底层配置的确定性手段。
最容易被忽略的点是:你查 SHOW FULL COLUMNS FROM table_name LIKE 'col_name' 看到的 Collation 值,未必就是 JOIN 实际生效的规则——如果字段定义没显式指定,它会继承表级甚至数据库级默认值,而不同版本 MySQL 默认值还可能不同。











