MySQL函数不适合复杂逻辑,因其本质是标量计算单元;多表JOIN、子查询、循环、异常分支会导致性能衰减与维护困难,且调试难、迁移成本高;仅适合纯计算、格式转换等无副作用操作。
不适合。MySQL 的 FUNCTION 本质是标量计算单元,不是通用逻辑容器。一旦塞入多表 JOIN、子查询嵌套、循环处理或异常分支,就会触发明显性能衰减和维护黑洞。
DETERMINISTIC 声明常被误用:实际依赖表数据时却标为确定性,导致查询缓存错乱或主从不一致SELECT 会阻塞并发:每个调用都走一遍全表扫描或索引查找,高并发下线程池迅速打满仅限纯计算、格式转换、简单条件映射这类无副作用操作。核心判断标准:输入完全来自参数,输出不依赖任何表数据,执行时间稳定在毫秒级。
DATE_FORMAT(NOW(), '%Y-%m-%d') 封装成 fn_today_str()
CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) 提取为 fn_mask_phone()
CASE status WHEN 1 THEN 'active' WHEN 0 THEN 'inactive' END 抽成 fn_status_label()
DELIMITER $$ CREATE FUNCTION fn_status_label(status TINYINT) RETURNS VARCHAR(20) READS SQL DATA DETERMINISTIC BEGIN RETURN CASE status WHEN 1 THEN 'active' WHEN 0 THEN 'inactive' ELSE 'unknown' END; END$$ DELIMITER ;
需要复用多表关联或带业务规则的逻辑,VIEW 比函数更安全,而真正复杂的流程必须交给应用代码。
user_profile_view 合并 users + profiles + roles,SQL 层可读性强,还能走索引
许函数中执行 CALL,强行绕过(如用 sys_exec)会破坏事务一致性立刻评估是否可拆解。重点看函数体里有没有 SELECT ... FROM、WHILE、REPEAT、INSERT/UPDATE 或对系统变量(如 @xxx)的读写。
PROCEDURE),且明确标注 MODIFIES SQL DATA
SYSBENCH 或真实流量对比函数调用 vs 应用层等效逻辑的 QPS 和延迟抖动函数不是语法糖,是隔离边界。越想让它干更多事,边界就越模糊,最后连 explain 都看不出瓶颈在哪。