MySQL 8.0+ 中字符串拼接应优先用 CONCAT_WS(),因其自动跳过 NULL、无需 IFNULL 嵌套且可读性与健壮性更优;CONCAT() 对 NULL 敏感,+ 和 || 在默认模式下不适用或存在类型转换风险。
CONCAT 函数在 MySQL 中到底快不快?
直接说结论:在 MySQL 8.0+ 中,
和
(加号)都不适用——MySQL 不支持用
拼接字符串(会转成数字相加),而
默认是逻辑或运算符,除非开启
SQL 模式。所以实际能选的只有
、
,或显式类型转换后用
。
常见错误现象:
返回
(因为
当作 OR 计算,两边转布尔为 false → 0);
返回
,不是
。
MySQL 5.7 默认关闭
,开启后
才等价于字符串拼接
MySQL 8.0 默认仍关闭该模式,不能依赖
安全拼接
对
敏感:任一参数为
,整个结果为
;可用
规避
为什么 CONCAT_WS 比 CONCAT 更适合多字段拼接?
(W S = With Separator)专为带分隔符的拼接设计,它自动跳过
参数,且只在非
值之间插入分隔符——这省去了大量
嵌套。
使用场景:生成 CSV 行、日志消息、路径拼接(如
)。
第一个参数必须是分隔符(可以是空字符串
),后续参数逐个判断是否
→
;而
→
性能上两者差异极小(函数调用开销远小于网络/磁盘 I/O),但可读性和健壮性明显更高
字符串拼接引发隐式类型转换的坑
MySQL 在拼接时会尝试把所有参数转为字符串,但规则容易误判:数值型字段(如
、
)会被转成“无格式”字符串,丢失前导零或科学计数法异常。
常见错误现象:
得到
(八进制解析+转十进制);
可能返回
或
,取决于版本和精度设置。
安全做法:显式用
或
,尤其对带格式需求的字段(如订单号、身份证号)
避免直接拼接
字段:
可能触发时区转换或截断,应先用
字符集不一致时(如 utf8mb4 列与 latin1 字符串拼接),可能报错
,需统一用
显式指定
真正影响性能的从来不是 CONCAT 本身
单次
调用耗时在纳秒级,比一次主键查询慢不到一个数量级。真正拖慢响应的,是拼接逻辑出现在 WHERE 或 ORDER BY 中导致无法使用索引,或在大结果集每行都执行拼接。
使用场景:报表导出、日志归档这类批量拼接,要注意是否在 SELECT 中对百万行做
——即使函数很快,内存和网络传输压力也会陡增。
高频拼接字段(如用户全名)建议建生成列(generated column)并索引:
避免在 JOIN 条件里拼接:
会让 a 表全表扫描
如果只是为展示用,前端拼接更灵活(尤其涉及国际化、空格/标点规则变化时)
最常被忽略的一点:拼接结果长度超过
会导致查询被截断或报错
,特别是拼接长文本字段(
)时,务必检查该变量值。
CONCAT()++||PIPES_AS_CONCATCONCAT()CONCAT_WS()CONCAT()SELECT 'a' || 'b';0||SELECT '1' + '2';3'12'PIPES_AS_CONCAT||||CONCAT()NULLNULLNULLCONCAT(IFNULL(a,''), IFNULL(b,''))CONCAT_WS()NULLNULLIFNULL()/user/123/profile''NULLCONCAT_WS('-', 'a', NULL, 'c')'a-c'CONCAT('a', NULL, 'c')NULLINTDECIMALCONCAT('ID:', 00123)'ID:123'CONCAT('val:', 1e4)'val:10000''val:1e4'CAST(col AS CHAR)CONVERT(col, CHAR)TIMESTAMPCONCAT('time:', create_time)DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s')Illegal mix of collationsCOLLATE utf8mb4_0900_as_csCONCAT()CONCAT(first_name, ' ', last_name)full_name VARCHAR(100) STORED AS (CONCAT(first_name, ' ', last_name))ON CONCAT(a.id, '_tmp') = b.keymax_allowed_packetPackets larger than max_allowed_packet are not allowedTEXT