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 年的日志),避免日志表过大。

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

相关推荐
不知更鸟6 小时前
Django 项目是什么
数据库·sqlite
有一个好名字9 小时前
MyBatis-Plus 三种数据库操作方式详解 + 常用方法大全
数据库·mybatis
-Xie-9 小时前
Redis(八)——多线程与单线程
java·数据库·redis
G探险者9 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
Albert Tan11 小时前
Oracle EBS R12.2.14 清理FND_LOBS并释放磁盘空间
数据库·oracle
L.EscaRC11 小时前
图数据库Neo4j原理与运用
数据库·oracle·neo4j
知己808011 小时前
docker搭建图数据库neo4j
数据库·docker·neo4j
TDengine (老段)11 小时前
什么是 TDengine IDMP?
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
谅望者11 小时前
数据分析笔记08:Python编程基础-数据类型与变量
数据库·笔记·python·数据分析·概率论