必须用sys.tables和QUOTENAME()双重校验表名合法性再删表,避免SQL注入与误删;PostgreSQL需通过pg_class和边界解析安全判定过期分区;MySQL应动态计算时间阈值并分批删除;跨库清理须统一适配information_schema元数据差异。

SQL Server里用sp_executesql动态删表前先校验表名合法性
直接拼接表名进DROP TABLE语句是高危操作,一旦变量被污染(比如注入了sys.tables; TRUNCATE TABLE users),整个库都可能被拖垮。必须用sys.tables和QUOTENAME()双重兜底。
- 先查
sys.tables确认表存在且属于dbo或指定schema,避免误删临时表或系统表 - 用
QUOTENAME(@table_name)包裹表名,自动处理中划线、空格、中文等非法字符 - 别用
EXEC('DROP TABLE ' + @table_name)——这是最常踩的坑,90%的线上误删都从这儿开始
示例:
IF EXISTS (SELECT 1 FROM sys.tables WHERE name = @table_name AND schema_id = SCHEMA_ID('dbo'))<br> EXEC sp_executesql N'DROP TABLE dbo.' + QUOTENAME(@table_name);
PostgreSQL中用pg_class判断分区表是否过期并触发DROP TABLE
PostgreSQL没内置“按时间自动删分区”机制,得靠pg_class和pg_partitioned_table反查分区键范围。重点不是删,而是怎么安全判定“该删”。
- 查
pg_class.relname匹配log_202301这类命名规则时,必须加AND relkind = 'r',排除索引、视图干扰 - 如果分区依据是
created_at字段,不能只看表名,得用pg_get_expr(relpartbound, oid)解析实际边界值,否则会漏删或错删 - 执行
DROP TABLE前加IF EXISTS,避免因并发导致报错中断后续清理
示例:
SELECT relname FROM pg_class c<br>JOIN pg_namespace n ON n.oid = c.relnamespace<br>WHERE n.nspname = 'public'<br> AND c.relname ~ '^log_\d{6}$'<br> AND c.relkind = 'r'<br> AND SUBSTRING(c.relname, 5, 6)::int < EXTRACT(YEAR FROM CURRENT_DATE)::int * 100 + EXTRACT(MONTH FROM CURRENT_DATE)::int - 6;
MySQL存储过程里用DATE_SUB(NOW(), INTERVAL 90 DAY)比硬写日期更可靠
有人把过期条件写成WHERE create_time < '2024-01-01',结果上线三个月后所有清理逻辑全失效——因为没人记得去改这个字符串。时间阈值必须动态算。
-
DATE_SUB(NOW(), INTERVAL 90 DAY)是MySQL最稳的写法,CURDATE()会丢掉时分秒,可能导致刚过期的数据被漏掉 - 如果日志表有大量数据,
DELETE单次删太多会锁表;改成LIMIT 10000分批删,并用ROW_COUNT()判断是否还有剩余 - 别在存储过程中用
TRUNCATE TABLE清历史表——它不走事务、无法回滚,且会重置自增ID,影响下游ETL依赖
跨数据库清理任务必须统一用information_schema查表结构
同一个清理脚本要在MySQL、PostgreSQL、SQL Server上跑,就不能依赖sys.tables或pg_class这种方言。唯一能共用的是information_schema.tables,但细节差异极大。
-
table_schema在MySQL里是数据库名,在PostgreSQL里是schema名,在SQL Server里对应TABLE_CATALOG——必须按目标库动态适配 -
table_name字段内容大小写敏感性不一致:PostgreSQL默认小写,SQL Server默认大写,查之前先UPPER()或LOWER()归一化 - 有些库(如旧版MySQL)不支持
information_schema里的create_time字段,得退回到查SHOW CREATE TABLE输出再正则提取
真正难的不是写一次删多少,而是让同一套逻辑在不同环境里不崩、不错、不漏——边界判断和元数据校验比删除动作本身重要十倍。










