先用SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'myapp' AND TABLE_NAME LIKE 'tmp\_%'查出指定库中带前缀的表名,再通过动态SQL逐条执行DROP TABLE IF EXISTS \table_name\``。

怎么用存储过程查出所有带前缀的表名
MySQL 本身不支持直接 DROP TABLE LIKE,得先拿到匹配的表名列表。关键不是“写个循环”,而是确保 INFORMATION_SCHEMA.TABLES 查询准确——必须限定 TABLE_SCHEMA(即数据库名),否则跨库误删风险极高。
常见错误是漏写 WHERE TABLE_SCHEMA = 'your_db_name',导致查到系统库或其它库的同名前缀表;或者用 LIKE 'prefix%' 时没加引号,SQL 直接报错。
- 务必显式指定数据库:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'myapp' AND TABLE_NAME LIKE 'tmp_%' - 前缀含下划线时注意转义:
LIKE 'log\_%' ESCAPE '\',否则_被当通配符匹配单字符 - 避免在生产库直接查
INFORMATION_SCHEMA大库——可能锁表或慢,先用SHOW TABLES LIKE 'tmp_%'快速验证模式是否匹配
存储过程中拼接并执行 DROP TABLE 语句
不能直接在存储过程里写 DROP TABLE table_name,因为表名是变量,必须用动态 SQL。核心是 PREPARE + EXECUTE,且每次只能执行一条 DROP——MySQL 不支持 DROP TABLE t1, t2, t3 动态拼接后一次性执行(除非你确认所有表都存在,且无外键依赖)。
容易踩的坑:拼接 SQL 时没加反引号,遇到带中划线或关键字的表名(如 user-order、order)直接报语法错误;或者没做空值判断,结果 SET @sql = CONCAT('DROP TABLE ', NULL) 导致后续 EXECUTE 失败。
- 表名必须用反引号包裹:
CONCAT('DROP TABLE `', table_name, '`') - 每次
EXECUTE前检查@sql是否为空:IF @sql IS NOT NULL THEN PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; - 不要试图一次拼多个表:
DROP TABLE `t1`, `t2`在动态 SQL 中风险高,单条更可控
外键约束导致 DROP 失败怎么办
如果要删的表被其它表的外键引用,DROP TABLE 会直接报错 ERROR 1217 (HY000): Cannot delete or update a parent row: a foreign key constraint fails。这不是存储过程写得不对,而是 MySQL 的强制保护机制。
解决思路不是关外键检查(SET FOREIGN_KEY_CHECKS = 0 风险太大),而是先删子表、再删父表,或按依赖顺序删。但批量删前缀表时通常无法预知依赖关系——最稳妥的做法是提前人工确认这些表是否独立,或改用 DROP TABLE IF EXISTS 避免中断整个过程。
- 加
IF EXISTS是底线:CONCAT('DROP TABLE IF EXISTS `', table_name, '`') - 如果明确知道有外键,先查
INFORMATION_SCHEMA.KEY_COLUMN_USAGE找出依赖关系,再分两轮删(先删被依赖的,再删依赖方) - 别在存储过程里自动关外键检查——万一中间出错,残留的
FOREIGN_KEY_CHECKS = 0会埋雷
为什么不用 shell 脚本或客户端工具直接删
存储过程看似重,但优势在于:所有操作在服务端完成,不依赖客户端环境;权限集中管控(只要存储过程有权限,调用者无需 DROP 权限);可嵌入定时任务或其它业务逻辑。而用 mysql -e "SHOW TABLES LIKE 'tmp_%'" 再管道给 xargs,容易因表名含空格、特殊字符或网络中断失败。
真正要注意的是权限和事务边界:存储过程默认不支持事务回滚 DDL 操作(DROP TABLE 会隐式提交),所以删一半出错,前面删掉的表无法还原。
- 执行前务必备份关键数据,或先用
RENAME TABLE把表改名(如加_to_drop后缀),确认无误再真删 - 存储过程里别写
COMMIT或ROLLBACK——DDL 自动提交,加了也没用 - 测试时永远先在副本库跑,哪怕只有一张测试表,也要看日志里实际执行的
DROP语句长什么样
最麻烦的从来不是写对存储过程,而是确认“这些表真的可以删”——名字像临时表,可能是某个服务正在用的归档分区表。删之前,去 PROCESSLIST 和慢查询日志里扫一眼有没有活跃关联。


















