直接drop function会阻塞正在执行的调用,因需获取排他mdl锁而等待活跃共享锁释放,表现为语句卡住、show processlist显示waiting for table metadata lock。

直接 DROP FUNCTION 会阻塞正在执行的调用吗
不会立即报错,但会进入元数据锁(MDL)等待队列。MySQL 在执行 DROP FUNCTION 前必须获取该函数的排他 MDL 锁,而此时若有其他会话正处在 CALL func_name() 或 SQL 中引用该函数(如 SELECT func_name(x)),它们已持有共享 MDL 锁——DROP 就会被挂起,直到所有活跃调用完成或超时(默认 lock_wait_timeout=31536000 秒,即一年)。现象是:你的 DROP 语句卡住不动,SHOW PROCESSLIST 里能看到状态为 Waiting for table metadata lock。
如何确认函数当前是否正被并发调用
MySQL 没有实时“谁在调用这个函数”的视图,但可通过间接方式排查:
- 查活跃会话中含该函数名的 SQL:
SELECT ID, USER, HOST, INFO FROM information_schema.PROCESSLIST WHERE INFO LIKE '%func_name%'; - 查最近执行过的慢日志(若开启):
mysqldumpslow -s t /var/log/mysql/mysql-slow.log | grep func_name - 检查应用层连接池监控(如 Prometheus + mysqld_exporter)是否有持续调用该函数的指标突增
- 注意:
INFORMATION_SCHEMA.ROUTINES只存定义,不反映运行态;不要依赖SHOW FUNCTION STATUS判断是否“正在被调用”
安全删除的实操步骤(顺序不能颠倒)
跳过任一环节都可能引发线上故障:
- 先停应用侧调用:通知上下游服务下线对该函数的引用,或通过配置中心关闭对应功能开关
- 再设只读窗口:在业务低峰期执行
SET SESSION sql_log_bin = 0;(仅限必要场景,慎用),避免 binlog 写入干扰主从 - 然后验证无活跃调用:
SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE INFO LIKE '%func_name%';返回 0 才继续 - 最后执行删除:
DROP FUNCTION IF EXISTS func_name;——IF EXISTS防语法报错,但不解决锁竞争 - 删完立刻验证:
SELECT COUNT(*) FROM information_schema.ROUTINES WHERE ROUTINE_NAME = 'func_name' AND ROUTINE_SCHEMA = DATABASE() AND ROUTINE_TYPE = 'FUNCTION';必须返回 0
为什么不能靠重命名或注释替代删除
重命名(如 RENAME FUNCTION)在 MySQL 中不支持;注释函数体(如把 BEGIN ... END 改成 BEGIN RETURN NULL; END)看似“禁用”,但风险更高:
- 函数仍存在于
information_schema.ROUTINES,权限检查、依赖扫描、备份恢复都照常处理它 - 应用若未及时更新,调用仍会成功返回 NULL 或错误值,问题更隐蔽
- 后续真正要删时,仍得面对同样的并发调用冲突,没省一步
- 函数定义变空后,某些 ORM 或 SQL 解析器可能抛出语法异常,而非预期的逻辑错误
真正麻烦的从来不是那条 DROP FUNCTION 语句本身,而是你无法精确知道哪条应用线程正拿着它的句柄在跑——这要求你对调用链路有端到端可观测能力,而不是只盯着数据库命令行。











