mysql字符串拼接用concat()遇null即返null,应改用concat_ws()或ifnull兜底;substr/substring等价且支持负数截取;replace大小写敏感且全局替换;函数用于where将导致索引失效。

MySQL 字符串拼接用 CONCAT(),但空值会让整结果变 NULL
很多人写 CONCAT(name, ' - ', phone) 发现某条记录字段为 NULL 时,整条拼出来是 NULL,不是预期的 '张三 - ' 或 '张三 - 138****'。这是因为 CONCAT() 遇到任意参数为 NULL 就直接返回 NULL,不跳过也不转空字符串。
- 用
CONCAT_WS()更稳妥:它第一个参数是分隔符,自动跳过NULL参数,比如CONCAT_WS(' - ', name, phone)会把name是NULL的记录变成' - 138****' - 真要保留
CONCAT(),得手动兜底:CONCAT(IFNULL(name, ''), ' - ', IFNULL(phone, '')) -
CONCAT()在 MySQL 5.7+ 支持任意数量参数;低版本只支持两个,多参数需嵌套
截取字符串别硬背 SUBSTR() 和 SUBSTRING() 区别
这两个函数完全等价,SUBSTRING(str, pos, len) 就是 SUBSTR(str, pos, len) 的同义词,官方文档都写明了可互换。真正要注意的是位置起始——MySQL 从 1 开始计数,不是 0。
- 想取后 3 位?别写
SUBSTR(col, -3)然后发现没效果——其实可以,-n表示“从末尾倒数第 n 个字符开始”,SUBSTR('abcde', -2)返回'de' - 长度参数
len可省略,省略时默认取到末尾;但若pos超出字符串长度,返回空字符串(不是报错) - 中文字符没问题,UTF-8 下按字符截取,不是按字节,前提是列字符集是
utf8mb4且连接也用了该编码
REPLACE() 是大小写敏感的,别指望它自动处理大小写
REPLACE(col, 'old', 'new') 只替换完全匹配的子串,且严格区分大小写。比如 REPLACE('Apple', 'apple', 'orange') 不会生效,因为首字母大小写不一致。
- 需要忽略大小写替换?MySQL 原生没提供,得组合函数:
REPLACE(LOWER(col), 'apple', 'orange')再配合大小写还原逻辑(通常不推荐,易出错) - 更实际的做法是:先用
WHERE LOWER(col) LIKE '%apple%'找出目标行,再在应用层或存储过程中做大小写无关替换 -
REPLACE()会全局替换所有匹配项,不是只换第一次;如果只想换前 N 次,得用自定义函数或应用层处理
性能和索引:这些函数会让 WHERE 条件失效
只要在 WHERE 子句里对字段用 CONCAT()、SUBSTR()、REPLACE(),哪怕只是简单拼接,该字段就无法走索引。比如 WHERE CONCAT(first_name, last_name) = 'ZhangSan',即使 first_name 和 last_name 都有索引,也会全表扫描。
- 能前置计算就前置:比如把昵称拼接逻辑放到写入时存进新字段
full_name,并给它加索引 - 模糊查询想用前缀?用
LIKE 'abc%',别用SUBSTR(col, 1, 3) = 'abc'—— 后者无法利用索引 - 临时需要函数过滤又数据量大?考虑生成列(Generated Column)+ 索引:MySQL 5.7+ 支持
ALTER TABLE t ADD full_name VARCHAR(100) STORED AS (CONCAT(first, last)),再对full_name加索引
字符串函数本身不慢,慢的是它们切断了优化器用索引的路径。线上查得慢,先看执行计划里有没有 type: ALL,再检查 WHERE 里是否包裹了函数。











