SQL Server 创建一个删除分表的作业,每月执行一次,删除表的逻辑放到存储过程里

创建一个每月存储过程 (包含分表删除逻辑)+ SQL Server 代理作业(每月自动执行),支持按日期范围删除过期分表,且包含日志记录和安全校验。

步骤 1:创建删除分表的存储过程(带日志 + 安全校验)

sql

复制代码
USE [你的数据库名]; -- 替换为分表所在数据库
GO

-- 创建删除日志表(记录次删除记录都将被记录,便于审计)
IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'DropTableLog' AND schema_id = SCHEMA_ID('dbo'))
BEGIN
    CREATE TABLE [dbo].[DropTableLog] (
        LogId INT IDENTITY(1,1) PRIMARY KEY,
        TableName NVARCHAR(100) NOT NULL, -- 被删除的表名
        DropTime DATETIME NOT NULL DEFAULT GETDATE(), -- 删除时间
        DropResult NVARCHAR(50) NOT NULL, -- 结果:成功/失败
        ErrorMessage NVARCHAR(MAX) NULL -- 错误信息(失败时记录)
    );
    PRINT '已创建删除日志表:DropTableLog';
END
GO

-- 创建删除分表的存储过程
CREATE OR ALTER PROCEDURE [dbo].[sp_DropExpiredShardingTables]
    @prefix NVARCHAR(50) = 'TestResultDetail', -- 分表前缀(如TestResultDetail)
    @keepMonths INT = 6, -- 保留最近N个月的分表(超过则删除)
    @tableCount INT = 3 -- 每月分表数量(如每月3张)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE 
        @currentYearMonth NVARCHAR(6),
        @expireYearMonth NVARCHAR(6), -- 过期年月(需删除的年月)
        @j INT = 1,
        @tableName NVARCHAR(100),
        @sql NVARCHAR(MAX),
        @errorMsg NVARCHAR(MAX);

    -- 计算过期年月(当前时间减去保留月份)
    SET @expireYearMonth = FORMAT(DATEADD(MONTH, -@keepMonths, GETDATE()), 'yyyyMM');
    PRINT '开始删除 [' + @prefix + '] 前缀、' + @expireYearMonth + ' 及之前的分表...';

    -- 从最早可能的分表年月开始遍历(这里从200001开始,可根据实际调整)
    SET @currentYearMonth = '200001';
    WHILE @currentYearMonth <= @expireYearMonth
    BEGIN
        SET @j = 1;
        WHILE @j <= @tableCount
        BEGIN
            -- 生成分表名(如TestResultDetail2025111)
            SET @tableName = @prefix + @currentYearMonth + CAST(@j AS NVARCHAR(1));
            
            BEGIN TRY
                -- 检查表是否存在
                IF EXISTS (
                    SELECT 1 FROM sys.tables 
                    WHERE name = @tableName AND schema_id = SCHEMA_ID('dbo')
                )
                BEGIN
                    -- 执行删除
                    SET @sql = N'DROP TABLE [dbo].[' + @tableName + N'];';
                    EXEC sp_executesql @sql;
                    
                    -- 记录成功日志
                    INSERT INTO [dbo].[DropTableLog] (TableName, DropResult)
                    VALUES (@tableName, '成功');
                    PRINT '已删除表:' + @tableName;
                END
                ELSE
                BEGIN
                    -- 表不存在,记录日志(可选)
                    INSERT INTO [dbo].[DropTableLog] (TableName, DropResult)
                    VALUES (@tableName, '表不存在,跳过');
                    PRINT '表不存在,跳过:' + @tableName;
                END
            END TRY
            BEGIN CATCH
                -- 捕获错误,记录日志
                SET @errorMsg = ERROR_MESSAGE();
                INSERT INTO [dbo].[DropTableLog] (TableName, DropResult, ErrorMessage)
                VALUES (@tableName, '失败', @errorMsg);
                PRINT '删除失败:' + @tableName + ',原因:' + @errorMsg;
            END CATCH

            SET @j = @j + 1;
        END

        -- 切换到下一个月(处理月份进位,如202512→202601)
        SET @currentYearMonth = FORMAT(
            DATEADD(MONTH, 1, CONVERT(DATETIME, @currentYearMonth + '01', 112)), 
            'yyyyMM'
        );
    END

    PRINT '分表删除任务完成,详情请查看 DropTableLog 表';
END
GO

步骤 2:创建 SQL Server 代理作业(每月自动执行)

通过作业定期调用存储过程,实现每月自动删除过期分表。

方式 1:SSMS 图形界面创建
  1. 打开 SSMS,展开SQL Server 代理 → 右键作业新建作业
    • 常规 选项卡:

      • 作业名称:Job_DropExpiredShardingTables(自定义)。
      • 描述:每月删除过期的分表(保留最近6个月)
    • 步骤 选项卡:

      • 新建步骤,名称:Step1_ExecuteDrop

      • 数据库:选择分表所在的数据库。

      • 命令: sql

        复制代码
        -- 调用存储过程,保留最近6个月的分表(可调整参数)
        EXEC [dbo].[sp_DropExpiredShardingTables] 
            @prefix = 'TestResultDetail', 
            @keepMonths = 6, 
            @tableCount = 3;
    • 计划 选项卡:

      • 新建计划,名称:MonthlyLastDay(每月最后一天执行)。
      • 频率:每月 ,执行时间:23:00:00(避开业务高峰)。
      • 高级:设置 "当月最后一天" 执行(需手动选择,或用 T-SQL 脚本设置)。
  2. 保存作业。
方式 2:T-SQL 脚本创建作业(推荐,精确控制每月最后一天)

sql

复制代码
USE [msdb];
GO

-- 创建作业
EXEC dbo.sp_add_job
    @job_name = N'Job_DropExpiredShardingTables',
    @enabled = 1,
    @description = N'每月删除过期的分表(保留最近6个月)';

-- 创建作业步骤
EXEC dbo.sp_add_jobstep
    @job_name = N'Job_DropExpiredShardingTables',
    @step_name = N'Step1_ExecuteDrop',
    @subsystem = N'TSQL',
    @command = N'
        EXEC [dbo].[sp_DropExpiredShardingTables] 
            @prefix = ''TestResultDetail'', 
            @keepMonths = 6, 
            @tableCount = 3;
    ',
    @database_name = N'你的数据库名'; -- 替换为实际数据库名

-- 创建作业计划(每月最后一天23点执行)
EXEC dbo.sp_add_jobschedule
    @job_name = N'Job_DropExpiredShardingTables',
    @name = N'MonthlyLastDay_23h',
    @freq_type = 16, -- 16=每月
    @freq_interval = 1, -- 每月1次
    @freq_recurrence_factor = 1, -- 每1个月
    @active_start_time = 230000, -- 23:00:00
    @freq_relative_interval = 16, -- 16=当月最后一天
    @freq_interval = 0; -- 配合relative_interval使用

-- 关联到本地服务器
EXEC dbo.sp_add_jobserver
    @job_name = N'Job_DropExpiredShardingTables',
    @server_name = N'(local)';
GO

关键优化点

  1. 自动化与可控性

    • 通过 @keepMonths 参数控制保留多久的分表(如保留 6 个月,自动删除更早的表),无需手动修改年月范围。
    • 作业计划设为每月最后一天 23 点,避开业务高峰,减少对系统的影响。
  2. 安全性与可追溯

    • 所有删除操作记录到 DropTableLog 表,包含表名、时间、结果和错误信息,便于审计和排查问题。
    • 异常捕获机制:单个表删除失败不会影响其他表,错误信息会被记录。
  3. 灵活性

    • 支持自定义分表前缀(@prefix)、每月分表数量(@tableCount),适配不同分表规则。
    • 如需调整保留时长,只需修改存储过程的 @keepMonths 参数(如改为 3 个月)。

验证与维护

  1. 手动测试 :执行 EXEC [dbo].[sp_DropExpiredShardingTables] @keepMonths = 12;(保留 12 个月,避免误删),检查 DropTableLog 确认结果。
  2. 作业历史:通过作业的 "查看历史记录" 确认每月执行情况。
  3. 日志清理 :定期清理 DropTableLog 表(如保留 1 年的日志),避免日志表过大。

此方案可长期稳定运行,自动清理过期分表,降低人工维护成本。

相关推荐
GottdesKrieges3 分钟前
通过obd升级OceanBase数据库
数据库·oracle·oceanbase
TiDB 社区干货传送门12 分钟前
【附操作指南】从 Oceanbase 增量数据同步到 TiDB
linux·服务器·数据库·tidb·oceanbase
光影少年23 分钟前
postgrsql和mysql区别?
数据库·mysql·postgresql
Hello.Reader1 小时前
Flink SQL Window Top-N窗口榜单的正确打开方式
数据库·sql·flink
wsx_iot1 小时前
MySQL 的 MVCC(多版本并发控制)详解
数据库·mysql
Shingmc31 小时前
MySQL表的增删改查
数据库·mysql
敲上瘾1 小时前
MySQL主从集群解析:从原理到Docker实战部署
android·数据库·分布式·mysql·docker·数据库架构
电子_咸鱼1 小时前
【QT——信号和槽(1)】
linux·c语言·开发语言·数据库·c++·git·qt
pandarking1 小时前
[CTF]攻防世界:web-unfinish(sql二次注入)
前端·数据库·sql·web安全·ctf
程序猿20231 小时前
MySQL索引性能分析
数据库·mysql