SQL Server数据自动清理系统最终版(C# WinForms完整源码)

SQL Server数据自动清理系统最终版(C# WinForms完整源码)

📋 项目简介

这是一个完整的SQL Server数据自动清理系统,包含数据库脚本、C#后端代码和WinForms前端界面。系统支持按数量和按日期两种清理模式,具有可视化配置管理、定时任务调度和详细日志记录功能。

📁 项目结构

复制代码
AutoCleanupSystem/
│
├── SQL/                    # SQL脚本文件
│   ├── 01_Database.sql    # 数据库创建脚本
│   ├── 02_Tables.sql      # 表结构脚本
│   ├── 03_Procedures.sql  # 存储过程脚本
│   └── 04_Jobs.sql        # 作业创建脚本
│
├── CSharp/                 # C#源代码
│   ├── DatabaseHelperT.cs  # 数据访问层
│   ├── MainFormT.cs        # 主窗体
│   ├── ConfigDialogT.cs    # 配置对话框
│   └── Models/             # 数据模型
│
├── Config/                 # 配置文件
│   └── App.config          # 应用程序配置
│
└── README.md              # 项目说明文档

🗄️ 1. 数据库脚本 (完整版)

1.1 数据库和表结构创建

sql 复制代码
-- ============================================================
-- 数据库自动清理系统 - 完整SQL脚本
-- ============================================================

-- 第一部分:创建数据库和表
SET NOCOUNT ON;
PRINT '开始部署数据库自动清理系统...';

-- 1. 创建管理数据库
USE master;
GO

IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'AutoCleanupDBT')
BEGIN
    CREATE DATABASE AutoCleanupDBT;
    ALTER DATABASE AutoCleanupDBT SET RECOVERY SIMPLE;
    PRINT '✅ 数据库 AutoCleanupDBT 创建完成';
END
ELSE
BEGIN
    PRINT 'ℹ️ 数据库 AutoCleanupDBT 已存在';
END
GO

USE AutoCleanupDBT;
GO

-- 2. 创建清理日志表
IF OBJECT_ID('dbo.CleanupLog', 'U') IS NULL
BEGIN
    CREATE TABLE dbo.CleanupLog
    (
        LogId BIGINT PRIMARY KEY IDENTITY(1,1),
        TableName NVARCHAR(100) NOT NULL,
        CleanType NVARCHAR(50) NOT NULL,
        DeletedRows INT DEFAULT 0,
        OldRowCount BIGINT NULL,
        NewRowCount BIGINT NULL,
        StartTime DATETIME DEFAULT GETDATE(),
        EndTime DATETIME NULL,
        DurationMs INT NULL,
        Status NVARCHAR(20) DEFAULT 'Success',
        ErrorMessage NVARCHAR(MAX) NULL
    );
    
    CREATE INDEX IX_CleanupLog_StartTime ON dbo.CleanupLog(StartTime DESC);
    PRINT '✅ 清理日志表创建完成';
END
GO

-- 3. 创建配置表
IF OBJECT_ID('dbo.CleanupConfig', 'U') IS NULL
BEGIN
    CREATE TABLE dbo.CleanupConfig
    (
        ConfigId INT PRIMARY KEY IDENTITY(1,1),
        ConfigName NVARCHAR(100) NOT NULL,
        DatabaseName NVARCHAR(100) DEFAULT 'WB_Front_endX',
        TableName NVARCHAR(100) DEFAULT 'WB_Front_end_shijianzhubiao',
        CleanMode INT DEFAULT 1,              -- 1:按数量, 2:按日期
        MaxRows INT DEFAULT 1000000,         -- 保留行数
        KeepDays INT DEFAULT 90,             -- 保留天数
        Enabled BIT DEFAULT 1,               -- 是否启用
        BatchSize INT DEFAULT 5000,          -- 批处理大小
        BatchDelay INT DEFAULT 50,           -- 批处理延迟(ms)
        LastCleanTime DATETIME NULL,         -- 最后清理时间
        CreatedTime DATETIME DEFAULT GETDATE(),
        UpdatedTime DATETIME DEFAULT GETDATE(),
        Description NVARCHAR(500) NULL       -- 配置描述
    );
    
    PRINT '✅ 配置表创建完成';
    
    -- 插入默认配置
    INSERT INTO dbo.CleanupConfig 
        (ConfigName, CleanMode, MaxRows, KeepDays, Enabled, Description)
    VALUES 
        ('默认按数量清理', 1, 1000000, NULL, 1, '保留100万条最新数据'),
        ('默认按日期清理', 2, NULL, 90, 1, '保留90天内数据'),
        ('严格清理策略', 1, 500000, 60, 0, '保留50万条或60天内数据(未启用)');
    
    PRINT '✅ 默认配置插入完成';
END
GO

1.2 存储过程脚本

sql 复制代码
-- 第二部分:创建存储过程
PRINT '开始创建存储过程...';

-- 1. 按数量清理存储过程
IF OBJECT_ID('dbo.usp_CleanupByRows', 'P') IS NOT NULL 
    DROP PROCEDURE dbo.usp_CleanupByRows;
GO

CREATE PROCEDURE dbo.usp_CleanupByRows
    @MaxRows INT,
    @BatchSize INT = 5000,
    @DelayMs INT = 50,
    @TestMode BIT = 0,
    @LogId BIGINT = NULL OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @DatabaseName NVARCHAR(100) = 'WB_Front_endX';
    DECLARE @TableName NVARCHAR(100) = 'WB_Front_end_shijianzhubiao';
    DECLARE @FullTableName NVARCHAR(500) = QUOTENAME(@DatabaseName) + '.dbo.' + QUOTENAME(@TableName);
    DECLARE @SQL NVARCHAR(MAX), @StartTime DATETIME = GETDATE(), @TotalDeleted INT = 0;
    DECLARE @OldRowCount BIGINT, @RowsToDelete BIGINT, @CurrentBatchSize INT;

    -- 获取当前总行数
    SET @SQL = N'SELECT @cnt = COUNT(*) FROM ' + @FullTableName + ' WITH (NOLOCK)';
    EXEC sp_executesql @SQL, N'@cnt BIGINT OUTPUT', @OldRowCount OUTPUT;

    SET @RowsToDelete = CASE WHEN @OldRowCount > @MaxRows THEN @OldRowCount - @MaxRows ELSE 0 END;

    -- 测试模式:只显示信息,不实际删除
    IF @TestMode = 1
    BEGIN
        PRINT '[测试模式] 按数量清理';
        PRINT '  当前行数: ' + CAST(@OldRowCount AS VARCHAR);
        PRINT '  保留行数: ' + CAST(@MaxRows AS VARCHAR);
        PRINT '  需要删除: ' + CAST(@RowsToDelete AS VARCHAR) + ' 行';
        PRINT '  批处理大小: ' + CAST(@BatchSize AS VARCHAR);
        RETURN;
    END

    -- 记录开始日志
    INSERT INTO dbo.CleanupLog (TableName, CleanType, OldRowCount, StartTime, Status)
    VALUES (@TableName, 'RowsOnly', @OldRowCount, @StartTime, 'Running');
    
    SET @LogId = SCOPE_IDENTITY();

    -- 执行清理(分批删除)
    IF @RowsToDelete > 0
    BEGIN
        WHILE @TotalDeleted < @RowsToDelete
        BEGIN
            SET @CurrentBatchSize = CASE 
                WHEN (@RowsToDelete - @TotalDeleted) > @BatchSize 
                THEN @BatchSize 
                ELSE (@RowsToDelete - @TotalDeleted) 
            END;
        
            -- 删除最早的数据(假设有ID字段)
            SET @SQL = N'DELETE TOP (@batch) FROM ' + @FullTableName 
                     + ' WHERE ID IN (SELECT TOP (@batch) ID FROM ' + @FullTableName 
                     + ' ORDER BY kaishishijian ASC)';
            
            EXEC sp_executesql @SQL, N'@batch INT', @batch = @CurrentBatchSize;

            SET @TotalDeleted += @@ROWCOUNT;
            
            -- 添加延迟,减少对数据库的影响
            IF @DelayMs > 0 
                WAITFOR DELAY '00:00:00.050';
                
            -- 每删除10000行输出一次进度
            IF @TotalDeleted % 10000 = 0 
                PRINT '  进度: 已删除 ' + CAST(@TotalDeleted AS VARCHAR) + ' 行';
        END
    END

    -- 记录完成日志
    UPDATE dbo.CleanupLog 
    SET DeletedRows = @TotalDeleted, 
        EndTime = GETDATE(), 
        DurationMs = DATEDIFF(MS, @StartTime, GETDATE()), 
        Status = 'Success',
        NewRowCount = (@OldRowCount - @TotalDeleted) 
    WHERE LogId = @LogId;
    
    PRINT '✅ 按数量清理完成: 删除 ' + CAST(@TotalDeleted AS VARCHAR) 
        + ' 行,耗时 ' + CAST(DATEDIFF(SECOND, @StartTime, GETDATE()) AS VARCHAR) + ' 秒';
END
GO

PRINT '✅ 存储过程 usp_CleanupByRows 创建完成';
GO

-- 2. 按日期清理存储过程
IF OBJECT_ID('dbo.usp_CleanupByDate', 'P') IS NOT NULL 
    DROP PROCEDURE dbo.usp_CleanupByDate;
GO

CREATE PROCEDURE dbo.usp_CleanupByDate
    @KeepDays INT,
    @BatchSize INT = 5000,
    @DelayMs INT = 50,
    @TestMode BIT = 0,
    @LogId BIGINT = NULL OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @DatabaseName NVARCHAR(100) = 'WB_Front_endX';
    DECLARE @TableName NVARCHAR(100) = 'WB_Front_end_shijianzhubiao';
    DECLARE @FullTableName NVARCHAR(500) = QUOTENAME(@DatabaseName) + '.dbo.' + QUOTENAME(@TableName);
    DECLARE @CutoffDate DATETIME = DATEADD(DAY, -@KeepDays, GETDATE());
    DECLARE @SQL NVARCHAR(MAX), @StartTime DATETIME = GETDATE(), @TotalDeleted INT = 0, @BatchDeleted INT = 1;
    DECLARE @OldRowCount BIGINT, @RowsToDelete INT;

    -- 获取当前总行数
    SET @SQL = N'SELECT @cnt = COUNT(*) FROM ' + @FullTableName + ' WITH (NOLOCK)';
    EXEC sp_executesql @SQL, N'@cnt BIGINT OUTPUT', @OldRowCount OUTPUT;

    -- 测试模式
    IF @TestMode = 1
    BEGIN
        -- 计算需要删除的行数
        SET @SQL = N'SELECT @cnt = COUNT(*) FROM ' + @FullTableName + ' WHERE kaishishijian < @cutoff';
        EXEC sp_executesql @SQL, N'@cutoff DATETIME, @cnt INT OUTPUT', 
            @cutoff = @CutoffDate, @cnt = @RowsToDelete OUTPUT;
            
        PRINT '[测试模式] 按日期清理';
        PRINT '  截止日期: ' + CONVERT(VARCHAR, @CutoffDate, 120);
        PRINT '  当前行数: ' + CAST(@OldRowCount AS VARCHAR);
        PRINT '  需要删除: ' + CAST(@RowsToDelete AS VARCHAR) + ' 行';
        PRINT '  批处理大小: ' + CAST(@BatchSize AS VARCHAR);
        RETURN;
    END

    -- 记录开始日志
    INSERT INTO dbo.CleanupLog (TableName, CleanType, OldRowCount, StartTime, Status)
    VALUES (@TableName, 'DateOnly', @OldRowCount, @StartTime, 'Running');
    
    SET @LogId = SCOPE_IDENTITY();

    -- 执行清理(分批删除)
    WHILE @BatchDeleted > 0
    BEGIN
        SET @SQL = N'DELETE TOP (@batch) FROM ' + @FullTableName 
                 + ' WHERE kaishishijian < @cutoff';
        
        EXEC sp_executesql @SQL, N'@batch INT, @cutoff DATETIME', 
            @batch = @BatchSize, @cutoff = @CutoffDate;
            
        SET @BatchDeleted = @@ROWCOUNT;
        SET @TotalDeleted += @BatchDeleted;
        
        -- 添加延迟
        IF @BatchDeleted > 0 AND @DelayMs > 0 
            WAITFOR DELAY '00:00:00.050';
            
        -- 每删除10000行输出一次进度
        IF @TotalDeleted % 10000 = 0 
            PRINT '  进度: 已删除 ' + CAST(@TotalDeleted AS VARCHAR) + ' 行';
    END

    -- 记录完成日志
    UPDATE dbo.CleanupLog 
    SET DeletedRows = @TotalDeleted, 
        EndTime = GETDATE(), 
        DurationMs = DATEDIFF(MS, @StartTime, GETDATE()), 
        Status = 'Success',
        NewRowCount = (@OldRowCount - @TotalDeleted) 
    WHERE LogId = @LogId;
    
    PRINT '✅ 按日期清理完成: 删除 ' + CAST(@TotalDeleted AS VARCHAR) 
        + ' 行,耗时 ' + CAST(DATEDIFF(SECOND, @StartTime, GETDATE()) AS VARCHAR) + ' 秒';
END
GO

PRINT '✅ 存储过程 usp_CleanupByDate 创建完成';
GO

-- 3. 主清理程序(简化版)
IF OBJECT_ID('dbo.usp_QuickCleanup', 'P') IS NOT NULL 
    DROP PROCEDURE dbo.usp_QuickCleanup;
GO

CREATE PROCEDURE dbo.usp_QuickCleanup
    @CleanMode INT = NULL,  -- 1:按数量, 2:按日期
    @TestMode BIT = 0
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @ConfigId INT, @ConfigName NVARCHAR(100), @Mode INT;
    DECLARE @MaxRows INT, @KeepDays INT, @BatchSize INT, @BatchDelay INT;
    
    -- 获取启用的配置
    IF @CleanMode IS NOT NULL
    BEGIN
        -- 获取指定模式的配置
        SELECT TOP 1 @ConfigId = ConfigId, @ConfigName = ConfigName, @Mode = CleanMode,
                     @MaxRows = MaxRows, @KeepDays = KeepDays, 
                     @BatchSize = BatchSize, @BatchDelay = BatchDelay
        FROM dbo.CleanupConfig 
        WHERE Enabled = 1 AND CleanMode = @CleanMode
        ORDER BY ConfigId;
    END
    ELSE
    BEGIN
        -- 获取第一个启用的配置
        SELECT TOP 1 @ConfigId = ConfigId, @ConfigName = ConfigName, @Mode = CleanMode,
                     @MaxRows = MaxRows, @KeepDays = KeepDays, 
                     @BatchSize = BatchSize, @BatchDelay = BatchDelay
        FROM dbo.CleanupConfig 
        WHERE Enabled = 1
        ORDER BY ConfigId;
    END

    IF @Mode IS NULL 
    BEGIN 
        PRINT '❌ 未找到启用的清理配置';
        RETURN; 
    END

    PRINT '开始执行清理...';
    PRINT '配置名称: ' + @ConfigName;
    PRINT '清理模式: ' + CASE @Mode WHEN 1 THEN '按数量清理' WHEN 2 THEN '按日期清理' ELSE '未知' END;
    
    DECLARE @LogId BIGINT;

    -- 根据模式调用相应的存储过程
    IF @Mode = 1  -- 按数量清理
    BEGIN
        IF @MaxRows IS NOT NULL AND @MaxRows > 0
        BEGIN
            EXEC dbo.usp_CleanupByRows 
                @MaxRows = @MaxRows, 
                @BatchSize = @BatchSize, 
                @DelayMs = @BatchDelay,
                @TestMode = @TestMode,
                @LogId = @LogId OUTPUT;
        END
    END
    ELSE IF @Mode = 2  -- 按日期清理
    BEGIN
        IF @KeepDays IS NOT NULL AND @KeepDays > 0
        BEGIN
            EXEC dbo.usp_CleanupByDate 
                @KeepDays = @KeepDays, 
                @BatchSize = @BatchSize, 
                @DelayMs = @BatchDelay,
                @TestMode = @TestMode,
                @LogId = @LogId OUTPUT;
        END
    END

    -- 更新配置的最后执行时间
    IF @TestMode = 0 AND @LogId IS NOT NULL
    BEGIN
        UPDATE dbo.CleanupConfig 
        SET LastCleanTime = GETDATE(), UpdatedTime = GETDATE() 
        WHERE ConfigId = @ConfigId;
    END
    
    PRINT '清理流程结束';
END
GO

PRINT '✅ 存储过程 usp_QuickCleanup 创建完成';
GO

-- 4. 获取表统计信息
IF OBJECT_ID('dbo.usp_GetTableStats', 'P') IS NOT NULL 
    DROP PROCEDURE dbo.usp_GetTableStats;
GO

CREATE PROCEDURE dbo.usp_GetTableStats
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @FullTableName NVARCHAR(500) = '[WB_Front_endX].dbo.[WB_Front_end_shijianzhubiao]';
    DECLARE @SQL NVARCHAR(MAX), @Total BIGINT, @MinDate DATETIME, @MaxDate DATETIME;
    DECLARE @Rows30Days BIGINT, @Rows90Days BIGINT, @Rows180Days BIGINT;

    BEGIN TRY
        -- 基本统计
        SET @SQL = N'SELECT @Total = COUNT(*), @Min = MIN(kaishishijian), @Max = MAX(kaishishijian) 
                     FROM ' + @FullTableName + ' WITH (NOLOCK)';
        
        EXEC sp_executesql @SQL, 
            N'@Total BIGINT OUTPUT, @Min DATETIME OUTPUT, @Max DATETIME OUTPUT', 
            @Total = @Total OUTPUT, @Min = @MinDate OUTPUT, @Max = @MaxDate OUTPUT;

        -- 各时间段统计
        SET @SQL = N'SELECT @Rows = COUNT(*) FROM ' + @FullTableName 
                 + ' WITH (NOLOCK) WHERE kaishishijian >= DATEADD(DAY, -30, GETDATE())';
        EXEC sp_executesql @SQL, N'@Rows BIGINT OUTPUT', @Rows = @Rows30Days OUTPUT;
    
        SET @SQL = N'SELECT @Rows = COUNT(*) FROM ' + @FullTableName 
                 + ' WITH (NOLOCK) WHERE kaishishijian >= DATEADD(DAY, -90, GETDATE())';
        EXEC sp_executesql @SQL, N'@Rows BIGINT OUTPUT', @Rows = @Rows90Days OUTPUT;
        
        SET @SQL = N'SELECT @Rows = COUNT(*) FROM ' + @FullTableName 
                 + ' WITH (NOLOCK) WHERE kaishishijian >= DATEADD(DAY, -180, GETDATE())';
        EXEC sp_executesql @SQL, N'@Rows BIGINT OUTPUT', @Rows = @Rows180Days OUTPUT;

        -- 输出结果
        PRINT '表统计信息: ' + @FullTableName;
        PRINT '总行数: ' + CAST(@Total AS VARCHAR) + ' 行';
        PRINT '数据时间范围: ' + ISNULL(CONVERT(VARCHAR, @MinDate, 120), 'N/A') 
              + ' 至 ' + ISNULL(CONVERT(VARCHAR, @MaxDate, 120), 'N/A');
        PRINT '最近30天数据: ' + CAST(@Rows30Days AS VARCHAR) + ' 行';
        PRINT '最近90天数据: ' + CAST(@Rows90Days AS VARCHAR) + ' 行';
        PRINT '最近180天数据: ' + CAST(@Rows180Days AS VARCHAR) + ' 行';
        
        -- 建议信息
        PRINT '';
        PRINT '清理建议:';
        IF @Total > 1000000
            PRINT '  ⚠️ 数据量超过100万行,建议执行按数量清理';
        IF DATEDIFF(DAY, @MinDate, GETDATE()) > 180
            PRINT '  ⚠️ 存在超过180天的历史数据,建议执行按日期清理';
        IF @Rows30Days < @Total * 0.1
            PRINT '  ⚠️ 近期数据占比过低,建议调整保留天数';
            
    END TRY
    BEGIN CATCH
        PRINT '❌ 获取统计信息失败: ' + ERROR_MESSAGE();
    END CATCH
END
GO

PRINT '✅ 存储过程 usp_GetTableStats 创建完成';
GO

-- 5. 执行所有启用的配置
IF OBJECT_ID('dbo.usp_ExecuteAllEnabledConfigs', 'P') IS NOT NULL 
    DROP PROCEDURE dbo.usp_ExecuteAllEnabledConfigs;
GO

CREATE PROCEDURE dbo.usp_ExecuteAllEnabledConfigs
    @TestMode BIT = 0
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @TotalConfigs INT = 0, @ProcessedConfigs INT = 0;
    DECLARE @ConfigId INT, @ConfigName NVARCHAR(100), @Mode INT;
    DECLARE @MaxRows INT, @KeepDays INT, @BatchSize INT, @BatchDelay INT;
    DECLARE @StartTime DATETIME = GETDATE();
    
    PRINT '开始执行所有启用的清理配置...';
    PRINT '执行时间: ' + CONVERT(VARCHAR, @StartTime, 120);
    PRINT '='.PadRight(50, '=');
    
    -- 获取所有启用的配置
    DECLARE config_cursor CURSOR LOCAL FAST_FORWARD FOR
    SELECT ConfigId, ConfigName, CleanMode, MaxRows, KeepDays, 
           BatchSize, BatchDelay
    FROM dbo.CleanupConfig 
    WHERE Enabled = 1
    ORDER BY ConfigId;
    
    OPEN config_cursor;
    FETCH NEXT FROM config_cursor INTO @ConfigId, @ConfigName, @Mode, 
                                       @MaxRows, @KeepDays, @BatchSize, @BatchDelay;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @TotalConfigs += 1;
        
        PRINT '执行配置: ' + @ConfigName + ' (ID: ' + CAST(@ConfigId AS VARCHAR) + ')';
        
        IF @TestMode = 1
        BEGIN
            PRINT '  [测试模式] 跳过实际清理';
            SET @ProcessedConfigs += 1;
        END
        ELSE
        BEGIN
            DECLARE @LogId BIGINT;
            
            IF @Mode = 1  -- 按数量清理
            BEGIN
                IF @MaxRows IS NOT NULL AND @MaxRows > 0
                BEGIN
                    BEGIN TRY
                        EXEC dbo.usp_CleanupByRows 
                            @MaxRows = @MaxRows, 
                            @BatchSize = @BatchSize, 
                            @DelayMs = @BatchDelay,
                            @TestMode = 0,
                            @LogId = @LogId OUTPUT;
                        SET @ProcessedConfigs += 1;
                    END TRY
                    BEGIN CATCH
                        PRINT '  ❌ 清理失败: ' + ERROR_MESSAGE();
                    END CATCH
                END
            END
            ELSE IF @Mode = 2  -- 按日期清理
            BEGIN
                IF @KeepDays IS NOT NULL AND @KeepDays > 0
                BEGIN
                    BEGIN TRY
                        EXEC dbo.usp_CleanupByDate 
                            @KeepDays = @KeepDays, 
                            @BatchSize = @BatchSize, 
                            @DelayMs = @BatchDelay,
                            @TestMode = 0,
                            @LogId = @LogId OUTPUT;
                        SET @ProcessedConfigs += 1;
                    END TRY
                    BEGIN CATCH
                        PRINT '  ❌ 清理失败: ' + ERROR_MESSAGE();
                    END CATCH
                END
            END
            
            -- 更新最后执行时间
            IF @TestMode = 0
            BEGIN
                UPDATE dbo.CleanupConfig 
                SET LastCleanTime = GETDATE(), UpdatedTime = GETDATE() 
                WHERE ConfigId = @ConfigId;
            END
        END
        
        FETCH NEXT FROM config_cursor INTO @ConfigId, @ConfigName, @Mode, 
                                           @MaxRows, @KeepDays, @BatchSize, @BatchDelay;
    END
    
    CLOSE config_cursor;
    DEALLOCATE config_cursor;
    
    -- 输出总结
    DECLARE @EndTime DATETIME = GETDATE();
    DECLARE @Duration INT = DATEDIFF(SECOND, @StartTime, @EndTime);
    
    PRINT '='.PadRight(50, '=');
    PRINT '执行完成';
    PRINT '总共发现 ' + CAST(@TotalConfigs AS VARCHAR) + ' 个启用配置';
    PRINT '成功执行 ' + CAST(@ProcessedConfigs AS VARCHAR) + ' 个配置';
    PRINT '总耗时: ' + CAST(@Duration AS VARCHAR) + ' 秒';
    PRINT '完成时间: ' + CONVERT(VARCHAR, @EndTime, 120);
    
    -- 记录总日志
    IF @TestMode = 0
    BEGIN
        INSERT INTO dbo.CleanupLog (TableName, CleanType, StartTime, EndTime, 
                                    DurationMs, Status, ErrorMessage)
        VALUES ('WB_Front_end_shijianzhubiao', 'AllEnabledConfigs', @StartTime, @EndTime,
                @Duration * 1000, 'Success', 
                '总共执行 ' + CAST(@ProcessedConfigs AS VARCHAR) + '/' 
                + CAST(@TotalConfigs AS VARCHAR) + ' 个配置');
    END
END
GO

PRINT '✅ 存储过程 usp_ExecuteAllEnabledConfigs 创建完成';
GO

-- 第三部分:创建定时作业
PRINT '开始配置SQL Server代理作业...';

-- 检查SQL Server代理是否启用
IF EXISTS (SELECT 1 FROM sys.configurations WHERE name = 'Agent XPs' AND value_in_use = 1)
BEGIN
    USE msdb;
    
    -- 删除已存在的作业
    IF EXISTS (SELECT name FROM sysjobs WHERE name = N'AutoCleanup_WB_Event_Job')
    BEGIN
        EXEC sp_delete_job @job_name = N'AutoCleanup_WB_Event_Job', @delete_unused_schedule = 1;
        PRINT 'ℹ️ 已删除现有作业';
    END

    DECLARE @jobId BINARY(16);
    
    -- 创建新作业
    EXEC sp_add_job @job_name = N'AutoCleanup_WB_Event_Job', 
                    @enabled = 1, 
                    @description = N'自动清理WB前端事件表(每日凌晨2点执行)',
                    @owner_login_name = N'sa', 
                    @job_id = @jobId OUTPUT;
    
    -- 添加作业步骤
    EXEC sp_add_jobstep @job_id = @jobId, 
                        @step_name = N'执行清理', 
                        @subsystem = N'TSQL', 
                        @command = N'USE AutoCleanupDBT; EXEC dbo.usp_ExecuteAllEnabledConfigs;',
                        @database_name = N'AutoCleanupDBT',
                        @on_success_action = 1,
                        @retry_attempts = 3,
                        @retry_interval = 5;

    -- 添加作业计划:每日凌晨2点执行
    EXEC sp_add_jobschedule @job_id = @jobId, 
                            @name = N'每日凌晨2点', 
                            @freq_type = 4, 
                            @freq_interval = 1, 
                            @active_start_time = 020000;
    
    -- 添加作业服务器
    EXEC sp_add_jobserver @job_id = @JobId, @server_name = N'(local)';
    
    PRINT '✅ SQL Server代理作业创建完成';
    PRINT '   - 作业名称: AutoCleanup_WB_Event_Job';
    PRINT '   - 执行时间: 每日 02:00';
    PRINT '   - 执行内容: 执行所有启用的清理配置';
END
ELSE
BEGIN
    PRINT '⚠️ SQL Server代理未开启,跳过作业创建';
    PRINT '   如需启用代理,请执行:';
    PRINT '   EXEC sp_configure ''show advanced options'', 1; RECONFIGURE;';
    PRINT '   EXEC sp_configure ''Agent XPs'', 1; RECONFIGURE;';
END
GO

-- 第四部分:初始化演示数据
USE AutoCleanupDBT;
GO

PRINT '=========================================';
PRINT '系统部署完成!';
PRINT '=========================================';
PRINT '';
PRINT '系统自检:';
PRINT '1. 显示表统计信息:';
EXEC dbo.usp_GetTableStats;
PRINT '';
PRINT '2. 显示当前配置:';
SELECT 
    ConfigId,
    ConfigName,
    CASE CleanMode 
        WHEN 1 THEN '按数量清理' 
        WHEN 2 THEN '按日期清理' 
        ELSE '未知' 
    END AS 清理模式,
    CASE 
        WHEN CleanMode = 1 AND MaxRows IS NOT NULL THEN CAST(MaxRows AS VARCHAR) + ' 行'
        WHEN CleanMode = 2 AND KeepDays IS NOT NULL THEN CAST(KeepDays AS VARCHAR) + ' 天'
        ELSE 'N/A' 
    END AS 保留条件,
    CASE Enabled 
        WHEN 1 THEN '启用' 
        ELSE '禁用' 
    END AS 状态,
    Description AS 描述
FROM dbo.CleanupConfig
ORDER BY ConfigId;
PRINT '';
PRINT '3. 测试清理功能(测试模式):';
PRINT '   - 测试按数量清理:';
EXEC dbo.usp_QuickCleanup @CleanMode = 1, @TestMode = 1;
PRINT '';
PRINT '   - 测试按日期清理:';
EXEC dbo.usp_QuickCleanup @CleanMode = 2, @TestMode = 1;
PRINT '';
PRINT '使用指南:';
PRINT '=========================================';
PRINT '1. 手动执行清理:';
PRINT '   -- 执行所有启用的配置:';
PRINT '   EXEC dbo.usp_ExecuteAllEnabledConfigs;';
PRINT '   -- 执行按数量清理:';
PRINT '   EXEC dbo.usp_QuickCleanup @CleanMode = 1;';
PRINT '   -- 执行按日期清理:';
PRINT '   EXEC dbo.usp_QuickCleanup @CleanMode = 2;';
PRINT '';
PRINT '2. 管理配置:';
PRINT '   -- 查看所有配置:';
PRINT '   SELECT * FROM dbo.CleanupConfig;';
PRINT '   -- 启用/禁用配置:';
PRINT '   UPDATE dbo.CleanupConfig SET Enabled = 1 WHERE ConfigId = 1;';
PRINT '   -- 查看清理日志:';
PRINT '   SELECT TOP 10 * FROM dbo.CleanupLog ORDER BY StartTime DESC;';
PRINT '';
PRINT '3. 定时作业:';
PRINT '   - 作业名称: AutoCleanup_WB_Event_Job';
PRINT '   - 执行时间: 每日 02:00';
PRINT '=========================================';
PRINT '';
PRINT '✅ 系统部署完成!请运行C#客户端程序进行可视化操作。';

💻 2. C#后端代码 (DatabaseHelperT.cs)

csharp 复制代码
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Collections.Generic;

namespace AutoCleanupSystem
{
    /// <summary>
    /// 数据库操作辅助类 - 完整版
    /// </summary>
    public class DatabaseHelperT
    {
        // 连接字符串(从配置文件读取)
        private static readonly string connectionString = 
            ConfigurationManager.ConnectionStrings["AutoCleanupDBT"]?.ConnectionString
            ?? "Data Source=.;Initial Catalog=AutoCleanupDBT;Integrated Security=True";

        #region 基础数据库操作
        
        /// <summary>
        /// 测试数据库连接
        /// </summary>
        public static bool TestConnection()
        {
            try
            {
                using (var conn = new SqlConnection(connectionString))
                {
                    conn.Open();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"数据库连接失败: {ex.Message}");
                return false;
            }
        }
        
        /// <summary>
        /// 执行非查询SQL
        /// </summary>
        public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters)
        {
            using (var conn = new SqlConnection(connectionString))
            using (var cmd = new SqlCommand(sql, conn))
            {
                conn.Open();
                if (parameters != null) 
                    cmd.Parameters.AddRange(parameters);
                return cmd.ExecuteNonQuery();
            }
        }
        
        /// <summary>
        /// 执行查询并返回DataTable
        /// </summary>
        public static DataTable ExecuteQuery(string sql, params SqlParameter[] parameters)
        {
            var dt = new DataTable();
            using (var conn = new SqlConnection(connectionString))
            using (var cmd = new SqlCommand(sql, conn))
            using (var adapter = new SqlDataAdapter(cmd))
            {
                if (parameters != null) 
                    cmd.Parameters.AddRange(parameters);
                adapter.Fill(dt);
            }
            return dt;
        }
        
        /// <summary>
        /// 执行存储过程
        /// </summary>
        public static DataTable ExecuteStoredProcedure(string procedureName, params SqlParameter[] parameters)
        {
            var dt = new DataTable();
            using (var conn = new SqlConnection(connectionString))
            using (var cmd = new SqlCommand(procedureName, conn))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                if (parameters != null) 
                    cmd.Parameters.AddRange(parameters);
                
                using (var adapter = new SqlDataAdapter(cmd))
                {
                    adapter.Fill(dt);
                }
            }
            return dt;
        }
        
        #endregion
        
        #region 清理功能
        
        /// <summary>
        /// 执行清理任务
        /// </summary>
        public static CleanupResult ExecuteCleanup(int? mode = null, bool testMode = false, int? configId = null)
        {
            var result = new CleanupResult 
            { 
                Success = false, 
                TestMode = testMode,
                ExecutionTime = DateTime.Now
            };
            
            var output = new StringBuilder();
            
            try
            {
                using (var conn = new SqlConnection(connectionString))
                using (var cmd = new SqlCommand("dbo.usp_QuickCleanup", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandTimeout = 3600; // 1小时超时
                    
                    // 添加参数
                    if (mode.HasValue)
                        cmd.Parameters.AddWithValue("@CleanMode", mode.Value);
                    else
                        cmd.Parameters.AddWithValue("@CleanMode", DBNull.Value);
                        
                    cmd.Parameters.AddWithValue("@TestMode", testMode);
                    
                    // 捕获输出消息
                    conn.InfoMessage += (s, e) => 
                    {
                        output.AppendLine(e.Message);
                        Console.WriteLine(e.Message); // 同时输出到控制台
                    };
                    
                    conn.Open();
                    cmd.ExecuteNonQuery();
                    
                    result.Success = true;
                    result.Output = output.ToString();
                }
            }
            catch (Exception ex)
            {
                result.ErrorMessage = ex.Message;
                output.AppendLine($"错误: {ex.Message}");
                result.Output = output.ToString();
            }
            
            return result;
        }
        
        /// <summary>
        /// 执行所有启用的配置
        /// </summary>
        public static CleanupResult ExecuteAllEnabledConfigs(bool testMode = false)
        {
            var result = new CleanupResult 
            { 
                Success = false, 
                TestMode = testMode,
                ExecutionTime = DateTime.Now
            };
            
            var output = new StringBuilder();
            
            try
            {
                using (var conn = new SqlConnection(connectionString))
                using (var cmd = new SqlCommand("dbo.usp_ExecuteAllEnabledConfigs", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandTimeout = 7200; // 2小时超时
                    
                    cmd.Parameters.AddWithValue("@TestMode", testMode);
                    
                    // 捕获输出消息
                    conn.InfoMessage += (s, e) => 
                    {
                        output.AppendLine(e.Message);
                        Console.WriteLine(e.Message);
                    };
                    
                    conn.Open();
                    cmd.ExecuteNonQuery();
                    
                    result.Success = true;
                    result.Output = output.ToString();
                }
            }
            catch (Exception ex)
            {
                result.ErrorMessage = ex.Message;
                output.AppendLine($"错误: {ex.Message}");
                result.Output = output.ToString();
            }
            
            return result;
        }
        
        /// <summary>
        /// 获取表统计信息
        /// </summary>
        public static string GetTableStatistics()
        {
            var output = new StringBuilder();
            
            try
            {
                using (var conn = new SqlConnection(connectionString))
                using (var cmd = new SqlCommand("dbo.usp_GetTableStats", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    
                    // 捕获输出消息
                    conn.InfoMessage += (sender, e) => 
                    {
                        output.AppendLine(e.Message);
                    };
                    
                    conn.Open();
                    cmd.ExecuteNonQuery();
                }
                
                // 如果存储过程没有输出,尝试直接查询
                if (output.Length == 0)
                {
                    output.AppendLine("表统计信息:");
                    output.AppendLine($"总行数: {GetRowCountDirect():N0} 行");
                }
            }
            catch (Exception ex)
            {
                output.AppendLine($"获取统计信息失败: {ex.Message}");
            }
            
            return output.ToString();
        }
        
        /// <summary>
        /// 直接获取表行数
        /// </summary>
        public static long GetRowCountDirect()
        {
            try
            {
                string sql = "SELECT COUNT(*) FROM [WB_Front_endX].[dbo].[WB_Front_end_shijianzhubiao]";
                using (var conn = new SqlConnection(connectionString))
                using (var cmd = new SqlCommand(sql, conn))
                {
                    conn.Open();
                    object result = cmd.ExecuteScalar();
                    if (result != null && result != DBNull.Value)
                    {
                        return Convert.ToInt64(result);
                    }
                }
                return 0;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"获取行数失败: {ex.Message}");
                return -1;
            }
        }
        
        #endregion
        
        #region 配置管理
        
        /// <summary>
        /// 获取所有配置
        /// </summary>
        public static DataTable GetConfigs()
        {
            return ExecuteQuery("SELECT * FROM dbo.CleanupConfig ORDER BY ConfigId");
        }
        
        /// <summary>
        /// 获取特定模式的配置
        /// </summary>
        public static DataTable GetConfigsByMode(int? mode = null)
        {
            string sql = "SELECT * FROM dbo.CleanupConfig WHERE Enabled = 1";
            
            if (mode.HasValue)
            {
                sql += " AND CleanMode = @Mode";
                var parameter = new SqlParameter("@Mode", mode.Value);
                return ExecuteQuery(sql, parameter);
            }
            
            return ExecuteQuery(sql);
        }
        
        /// <summary>
        /// 根据ID获取配置
        /// </summary>
        public static DataRow GetConfigById(int configId)
        {
            string sql = "SELECT * FROM dbo.CleanupConfig WHERE ConfigId = @ConfigId";
            var parameter = new SqlParameter("@ConfigId", configId);
            
            DataTable dt = ExecuteQuery(sql, parameter);
            return dt.Rows.Count > 0 ? dt.Rows[0] : null;
        }
        
        /// <summary>
        /// 更新配置
        /// </summary>
        public static bool UpdateConfig(int configId, int maxRows, int keepDays, int mode, bool enabled)
        {
            string sql = @"UPDATE dbo.CleanupConfig SET 
                            MaxRows = @MaxRows, 
                            KeepDays = @KeepDays, 
                            CleanMode = @Mode, 
                            Enabled = @Enabled, 
                            UpdatedTime = GETDATE() 
                          WHERE ConfigId = @Id";

            var parameters = new[]
            {
                new SqlParameter("@MaxRows", maxRows),
                new SqlParameter("@KeepDays", keepDays),
                new SqlParameter("@Mode", mode),
                new SqlParameter("@Enabled", enabled),
                new SqlParameter("@Id", configId)
            };

            return ExecuteNonQuery(sql, parameters) > 0;
        }
        
        /// <summary>
        /// 添加配置
        /// </summary>
        public static int AddConfig(string configName, int? maxRows, int? keepDays, int mode, bool enabled)
        {
            string sql = @"INSERT INTO dbo.CleanupConfig 
                          (ConfigName, MaxRows, KeepDays, CleanMode, Enabled, CreatedTime, UpdatedTime)
                          VALUES (@ConfigName, @MaxRows, @KeepDays, @Mode, @Enabled, GETDATE(), GETDATE());
                          SELECT SCOPE_IDENTITY();";

            var parameters = new[]
            {
                new SqlParameter("@ConfigName", configName),
                new SqlParameter("@MaxRows", maxRows ?? (object)DBNull.Value),
                new SqlParameter("@KeepDays", keepDays ?? (object)DBNull.Value),
                new SqlParameter("@Mode", mode),
                new SqlParameter("@Enabled", enabled)
            };

            using (var conn = new SqlConnection(connectionString))
            using (var cmd = new SqlCommand(sql, conn))
            {
                cmd.Parameters.AddRange(parameters);
                conn.Open();
                object result = cmd.ExecuteScalar();
                return Convert.ToInt32(result);
            }
        }
        
        /// <summary>
        /// 删除配置
        /// </summary>
        public static bool DeleteConfig(int configId)
        {
            string sql = "DELETE FROM dbo.CleanupConfig WHERE ConfigId = @ConfigId";
            var parameter = new SqlParameter("@ConfigId", configId);
            return ExecuteNonQuery(sql, parameter) > 0;
        }
        
        /// <summary>
        /// 切换配置启用状态
        /// </summary>
        public static bool ToggleConfigEnabled(int configId, bool enabled)
        {
            string sql = @"UPDATE dbo.CleanupConfig 
                          SET Enabled = @Enabled, UpdatedTime = GETDATE()
                          WHERE ConfigId = @ConfigId";
                          
            var parameters = new[]
            {
                new SqlParameter("@Enabled", enabled),
                new SqlParameter("@ConfigId", configId)
            };
            
            return ExecuteNonQuery(sql, parameters) > 0;
        }
        
        #endregion
        
        #region 日志查询
        
        /// <summary>
        /// 获取清理日志
        /// </summary>
        public static DataTable GetCleanupLogs(int top = 50, string cleanType = null)
        {
            string sql = $"SELECT TOP {top} * FROM dbo.CleanupLog";
            
            if (!string.IsNullOrEmpty(cleanType))
            {
                sql += " WHERE CleanType = @CleanType";
                var parameter = new SqlParameter("@CleanType", cleanType);
                return ExecuteQuery(sql, parameter);
            }
            
            sql += " ORDER BY StartTime DESC";
            return ExecuteQuery(sql);
        }
        
        /// <summary>
        /// 获取最近一次清理信息
        /// </summary>
        public static DataRow GetLastCleanupInfo()
        {
            DataTable dt = GetCleanupLogs(1);
            return dt.Rows.Count > 0 ? dt.Rows[0] : null;
        }
        
        #endregion
        
        #region SQL Server代理作业管理
        
        /// <summary>
        /// 获取作业详情
        /// </summary>
        public static DataTable GetJobDetails(string jobName = "AutoCleanup_WB_Event_Job")
        {
            string sql = @"  
            USE msdb; 
            SELECT 
                j.name AS JobName,
                j.enabled AS IsEnabled,
                j.description AS Description,
                CASE j.enabled WHEN 1 THEN '已启用' ELSE '已禁用' END AS Status,
                s.name AS ScheduleName,
                CASE s.freq_type
                    WHEN 1 THEN '一次性'
                    WHEN 4 THEN '每日'
                    WHEN 8 THEN '每周'
                    WHEN 16 THEN '每月'
                    ELSE '未知' 
                END AS Frequency,
                CASE 
                    WHEN s.freq_type = 4 THEN '每日 ' + 
                        RIGHT('0' + CAST(s.active_start_time/10000 AS VARCHAR),2) + ':' +
                        RIGHT('0' + CAST((s.active_start_time%10000)/100 AS VARCHAR),2)
                    ELSE '其他'
                END AS Schedule
            FROM sysjobs j
            LEFT JOIN sysjobschedules js ON j.job_id = js.job_id
            LEFT JOIN sysschedules s ON js.schedule_id = s.schedule_id
            WHERE j.name = @JobName";

            try
            {
                var parameter = new SqlParameter("@JobName", jobName);
                return ExecuteQuery(sql, parameter);
            }
            catch
            {
                return new DataTable();
            }
        }
        
        /// <summary>
        /// 启动作业
        /// </summary>
        public static bool StartAgentJob(string jobName = "AutoCleanup_WB_Event_Job")
        {
            try
            {
                string sql = @"  
                USE msdb; 
                EXEC sp_start_job @job_name = @JobName;";
                
                var parameter = new SqlParameter("@JobName", jobName);
                ExecuteNonQuery(sql, parameter);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"启动作业失败: {ex.Message}");
                return false;
            }
        }
        
        /// <summary>
        /// 创建或更新作业
        /// </summary>
        public static string CreateOrUpdateAgentJob()
        {
            try
            {
                // 检查作业是否存在
                DataTable jobDetails = GetJobDetails();
                
                if (jobDetails.Rows.Count > 0)
                {
                    return "作业已存在,无需重新创建";
                }
                else
                {
                    // 创建作业的SQL脚本
                    string createJobSql = @"
                    USE msdb;
                    DECLARE @jobId BINARY(16);
                    
                    -- 创建新作业
                    EXEC sp_add_job @job_name = N'AutoCleanup_WB_Event_Job', 
                                    @enabled = 1, 
                                    @description = N'自动清理WB前端事件表(每日凌晨2点执行)',
                                    @owner_login_name = N'sa', 
                                    @job_id = @jobId OUTPUT;
                    
                    -- 添加作业步骤
                    EXEC sp_add_jobstep @job_id = @jobId, 
                                        @step_name = N'执行清理', 
                                        @subsystem = N'TSQL', 
                                        @command = N'USE AutoCleanupDBT; EXEC dbo.usp_ExecuteAllEnabledConfigs;',
                                        @database_name = N'AutoCleanupDBT',
                                        @on_success_action = 1;
                    
                    -- 添加作业计划
                    EXEC sp_add_jobschedule @job_id = @jobId, 
                                            @name = N'每日凌晨2点', 
                                            @freq_type = 4, 
                                            @freq_interval = 1, 
                                            @active_start_time = 020000;
                    
                    -- 添加作业服务器
                    EXEC sp_add_jobserver @job_id = @jobId, @server_name = N'(local)';";
                    
                    ExecuteNonQuery(createJobSql);
                    return "作业创建成功";
                }
            }
            catch (Exception ex)
            {
                return $"创建作业失败: {ex.Message}";
            }
        }
        
        #endregion
        
        #region 表优化
        
        /// <summary>
        /// 优化表性能(重建索引)
        /// </summary>
        public static bool OptimizeTable()
        {
            try
            {
                string sql = @"
                USE WB_Front_endX;
                
                -- 重建所有索引
                ALTER INDEX ALL ON dbo.WB_Front_end_shijianzhubiao REBUILD;
                
                -- 更新统计信息
                UPDATE STATISTICS dbo.WB_Front_end_shijianzhubiao WITH FULLSCAN;
                
                -- 收缩数据库(可选)
                DBCC SHRINKDATABASE (WB_Front_endX, 10);";
                
                ExecuteNonQuery(sql);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"优化表失败: {ex.Message}");
                return false;
            }
        }
        
        #endregion
    }
    
    /// <summary>
    /// 清理结果实体类
    /// </summary>
    public class CleanupResult
    {
        public bool Success { get; set; }
        public string ErrorMessage { get; set; }
        public string Output { get; set; }
        public bool TestMode { get; set; }
        public DateTime ExecutionTime { get; set; }
        public int DeletedRows { get; set; }
        
        public CleanupResult()
        {
            Success = false;
            TestMode = false;
            ExecutionTime = DateTime.Now;
        }
    }
    
    /// <summary>
    /// 配置信息实体类
    /// </summary>
    public class ConfigInfo
    {
        public int ConfigId { get; set; }
        public string ConfigName { get; set; }
        public int CleanMode { get; set; }
        public int? MaxRows { get; set; }
        public int? KeepDays { get; set; }
        public bool Enabled { get; set; }
        public DateTime UpdatedTime { get; set; }
        
        public string ModeText
        {
            get
            {
                return CleanMode switch
                {
                    1 => "按数量清理",
                    2 => "按日期清理",
                    _ => "未知模式"
                };
            }
        }
        
        public string RetentionText
        {
            get
            {
                if (CleanMode == 1 && MaxRows.HasValue)
                    return $"保留 {MaxRows.Value:N0} 行";
                else if (CleanMode == 2 && KeepDays.HasValue)
                    return $"保留 {KeepDays.Value} 天";
                else
                    return "未设置";
            }
        }
    }
}

🖼️ 3. WinForms主界面 (MainFormT.cs)

csharp 复制代码
using System;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DemoAutoCleanT
{
    public partial class MainFormT : Form
    {
        // 定时器
        private Timer _statusTimer;
        private Timer _jobCheckTimer;
        private bool _isJobRunning = false;
        
        public MainFormT()
        {
            InitializeComponent();
            this.Load += MainFormT_Load;
            this.FormClosing += MainFormT_FormClosing;
        }
        
        private void MainFormT_Load(object sender, EventArgs e)
        {
            // 初始化界面
            InitializeUI();
            
            // 测试数据库连接
            TestDatabaseConnection();
            
            // 加载配置和数据
            LoadCleanupConfigs();
            LoadTableRowCount();
            LoadCleanupHistory();
            
            // 初始化定时器
            InitializeTimers();
        }
        
        private void MainFormT_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 清理资源
            if (_statusTimer != null)
            {
                _statusTimer.Stop();
                _statusTimer.Dispose();
            }
            
            if (_jobCheckTimer != null)
            {
                _jobCheckTimer.Stop();
                _jobCheckTimer.Dispose();
            }
        }
        
        #region 初始化方法
        
        private void InitializeUI()
        {
            // 设置窗体属性
            this.Text = "SQL Server数据自动清理系统";
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Size = new Size(1000, 700);
            
            // 创建标签页
            tabControl1 = new TabControl();
            tabControl1.Dock = DockStyle.Fill;
            tabControl1.SelectedIndexChanged += TabControl1_SelectedIndexChanged;
            
            // 创建三个标签页
            TabPage tabPage1 = CreateConfigTabPage();
            TabPage tabPage2 = CreateHistoryTabPage();
            TabPage tabPage3 = CreateSettingsTabPage();
            
            tabControl1.TabPages.Add(tabPage1);
            tabControl1.TabPages.Add(tabPage2);
            tabControl1.TabPages.Add(tabPage3);
            
            // 创建状态栏
            statusStrip1 = new StatusStrip();
            statusStrip1.Dock = DockStyle.Bottom;
            
            toolStripStatusLabel1 = new ToolStripStatusLabel("就绪");
            toolStripStatusLabel2 = new ToolStripStatusLabel("| 连接状态: 未知");
            toolStripStatusLabel3 = new ToolStripStatusLabel("| 配置数: 0");
            toolStripStatusLabel4 = new ToolStripStatusLabel("| 最后更新: --");
            toolStripProgressBar1 = new ToolStripProgressBar();
            toolStripProgressBar1.Visible = false;
            
            statusStrip1.Items.AddRange(new ToolStripItem[]
            {
                toolStripStatusLabel1,
                toolStripStatusLabel2,
                toolStripStatusLabel3,
                toolStripStatusLabel4,
                new ToolStripSeparator(),
                toolStripProgressBar1
            });
            
            // 添加到窗体
            this.Controls.Add(tabControl1);
            this.Controls.Add(statusStrip1);
        }
        
        private TabPage CreateConfigTabPage()
        {
            TabPage tabPage = new TabPage("清理配置");
            tabPage.BackColor = Color.White;
            
            // 创建按钮面板
            Panel buttonPanel = new Panel();
            buttonPanel.Dock = DockStyle.Top;
            buttonPanel.Height = 50;
            buttonPanel.BackColor = Color.LightGray;
            
            // 创建按钮
            btnExecute = CreateButton("执行清理", 20, 10, 100, 30);
            btnExecute.Click += BtnExecute_Click;
            
            btnStop = CreateButton("停止", 130, 10, 80, 30);
            btnStop.Click += BtnStop_Click;
            btnStop.Enabled = false;
            
            btnRefresh = CreateButton("刷新", 220, 10, 80, 30);
            btnRefresh.Click += BtnRefresh_Click;
            
            btnAddConfig = CreateButton("添加配置", 310, 10, 100, 30);
            btnAddConfig.Click += BtnAddConfig_Click;
            
            btnEditConfig = CreateButton("编辑配置", 420, 10, 100, 30);
            btnEditConfig.Click += BtnEditConfig_Click;
            
            btnDeleteConfig = CreateButton("删除配置", 530, 10, 100, 30);
            btnDeleteConfig.Click += BtnDeleteConfig_Click;
            
            btnOptimize = CreateButton("优化表", 640, 10, 80, 30);
            btnOptimize.Click += BtnOptimize_Click;
            
            // 创建数据统计标签
            lblDatacount = new Label();
            lblDatacount.Text = "表数据数量: 加载中...";
            lblDatacount.Location = new Point(730, 15);
            lblDatacount.Size = new Size(200, 20);
            lblDatacount.Font = new Font("Microsoft YaHei UI", 10, FontStyle.Bold);
            lblDatacount.ForeColor = Color.Blue;
            
            // 添加到按钮面板
            buttonPanel.Controls.AddRange(new Control[]
            {
                btnExecute, btnStop, btnRefresh, btnAddConfig,
                btnEditConfig, btnDeleteConfig, btnOptimize, lblDatacount
            });
            
            // 创建筛选面板
            Panel filterPanel = new Panel();
            filterPanel.Dock = DockStyle.Top;
            filterPanel.Height = 40;
            filterPanel.Top = 50;
            
            Label lblFilter = new Label();
            lblFilter.Text = "筛选模式:";
            lblFilter.Location = new Point(20, 10);
            lblFilter.Size = new Size(70, 20);
            
            comboBoxMode = new ComboBox();
            comboBoxMode.Location = new Point(100, 8);
            comboBoxMode.Size = new Size(150, 25);
            comboBoxMode.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBoxMode.Items.AddRange(new object[] { "全部模式", "仅按数量清理", "仅按日期清理" });
            comboBoxMode.SelectedIndex = 0;
            comboBoxMode.SelectedIndexChanged += ComboBoxMode_SelectedIndexChanged;
            
            filterPanel.Controls.Add(lblFilter);
            filterPanel.Controls.Add(comboBoxMode);
            
            // 创建数据网格
            dataGridViewConfigs = new DataGridView();
            dataGridViewConfigs.Dock = DockStyle.Fill;
            dataGridViewConfigs.Top = 90;
            dataGridViewConfigs.ReadOnly = true;
            dataGridViewConfigs.AllowUserToAddRows = false;
            dataGridViewConfigs.AllowUserToDeleteRows = false;
            dataGridViewConfigs.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dataGridViewConfigs.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            
            // 添加到标签页
            tabPage.Controls.Add(dataGridViewConfigs);
            tabPage.Controls.Add(filterPanel);
            tabPage.Controls.Add(buttonPanel);
            
            return tabPage;
        }
        
        private TabPage CreateHistoryTabPage()
        {
            TabPage tabPage = new TabPage("清理历史");
            tabPage.BackColor = Color.White;
            
            // 创建筛选面板
            Panel filterPanel = new Panel();
            filterPanel.Dock = DockStyle.Top;
            filterPanel.Height = 50;
            
            Label lblFilter = new Label();
            lblFilter.Text = "筛选类型:";
            lblFilter.Location = new Point(20, 15);
            lblFilter.Size = new Size(70, 20);
            
            comboBoxHistoryType = new ComboBox();
            comboBoxHistoryType.Location = new Point(100, 13);
            comboBoxHistoryType.Size = new Size(150, 25);
            comboBoxHistoryType.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBoxHistoryType.Items.AddRange(new object[] 
            { 
                "全部记录", 
                "按数量清理", 
                "按日期清理", 
                "执行所有配置" 
            });
            comboBoxHistoryType.SelectedIndex = 0;
            comboBoxHistoryType.SelectedIndexChanged += ComboBoxHistoryType_SelectedIndexChanged;
            
            btnRefreshHistory = CreateButton("刷新历史", 270, 10, 100, 30);
            btnRefreshHistory.Click += BtnRefreshHistory_Click;
            
            filterPanel.Controls.Add(lblFilter);
            filterPanel.Controls.Add(comboBoxHistoryType);
            filterPanel.Controls.Add(btnRefreshHistory);
            
            // 创建数据网格
            dataGridViewHistory = new DataGridView();
            dataGridViewHistory.Dock = DockStyle.Fill;
            dataGridViewHistory.Top = 50;
            dataGridViewHistory.ReadOnly = true;
            dataGridViewHistory.AllowUserToAddRows = false;
            dataGridViewHistory.AllowUserToDeleteRows = false;
            dataGridViewHistory.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dataGridViewHistory.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            
            // 添加到标签页
            tabPage.Controls.Add(dataGridViewHistory);
            tabPage.Controls.Add(filterPanel);
            
            return tabPage;
        }
        
        private TabPage CreateSettingsTabPage()
        {
            TabPage tabPage = new TabPage("系统设置");
            tabPage.BackColor = Color.White;
            
            // 创建分组容器
            GroupBox groupBox1 = new GroupBox();
            groupBox1.Text = "数据库连接";
            groupBox1.Location = new Point(20, 20);
            groupBox1.Size = new Size(900, 100);
            
            Label lblConn = new Label();
            lblConn.Text = "连接字符串:";
            lblConn.Location = new Point(20, 30);
            lblConn.Size = new Size(100, 20);
            
            textBoxConnectionString = new TextBox();
            textBoxConnectionString.Location = new Point(130, 27);
            textBoxConnectionString.Size = new Size(750, 25);
            textBoxConnectionString.ReadOnly = true;
            textBoxConnectionString.Multiline = true;
            textBoxConnectionString.Height = 60;
            
            groupBox1.Controls.Add(lblConn);
            groupBox1.Controls.Add(textBoxConnectionString);
            
            // 作业管理分组
            GroupBox groupBox2 = new GroupBox();
            groupBox2.Text = "SQL Server代理作业";
            groupBox2.Location = new Point(20, 140);
            groupBox2.Size = new Size(900, 150);
            
            btnCreateJobs = CreateButton("管理作业", 30, 40, 120, 35);
            btnCreateJobs.Click += BtnCreateJobs_Click;
            
            btnStartJob = CreateButton("立即执行", 170, 40, 120, 35);
            btnStartJob.Click += BtnStartJob_Click;
            
            textBoxJobStatus = new TextBox();
            textBoxJobStatus.Location = new Point(30, 90);
            textBoxJobStatus.Size = new Size(840, 45);
            textBoxJobStatus.Multiline = true;
            textBoxJobStatus.ReadOnly = true;
            textBoxJobStatus.Text = "作业状态: 未检查";
            
            groupBox2.Controls.Add(btnCreateJobs);
            groupBox2.Controls.Add(btnStartJob);
            groupBox2.Controls.Add(textBoxJobStatus);
            
            // 系统参数分组
            GroupBox groupBox3 = new GroupBox();
            groupBox3.Text = "系统参数";
            groupBox3.Location = new Point(20, 310);
            groupBox3.Size = new Size(900, 150);
            
            Label lblThreshold = new Label();
            lblThreshold.Text = "清理阈值(行):";
            lblThreshold.Location = new Point(30, 40);
            lblThreshold.Size = new Size(100, 20);
            
            numericUpDownCleanupThreshold = new NumericUpDown();
            numericUpDownCleanupThreshold.Location = new Point(140, 37);
            numericUpDownCleanupThreshold.Size = new Size(120, 25);
            numericUpDownCleanupThreshold.Minimum = 10000;
            numericUpDownCleanupThreshold.Maximum = 10000000;
            numericUpDownCleanupThreshold.Value = 1000000;
            
            Label lblInterval = new Label();
            lblInterval.Text = "状态刷新间隔(秒):";
            lblInterval.Location = new Point(30, 80);
            lblInterval.Size = new Size(120, 20);
            
            numericUpDownStatusInterval = new NumericUpDown();
            numericUpDownStatusInterval.Location = new Point(160, 77);
            numericUpDownStatusInterval.Size = new Size(100, 25);
            numericUpDownStatusInterval.Minimum = 10;
            numericUpDownStatusInterval.Maximum = 300;
            numericUpDownStatusInterval.Value = 30;
            
            checkBoxAutoStart = new CheckBox();
            checkBoxAutoStart.Text = "启动时自动连接数据库";
            checkBoxAutoStart.Location = new Point(300, 40);
            checkBoxAutoStart.Size = new Size(200, 20);
            checkBoxAutoStart.Checked = true;
            
            btnSaveSettings = CreateButton("保存设置", 30, 110, 100, 30);
            btnSaveSettings.Click += BtnSaveSettings_Click;
            
            groupBox3.Controls.Add(lblThreshold);
            groupBox3.Controls.Add(numericUpDownCleanupThreshold);
            groupBox3.Controls.Add(lblInterval);
            groupBox3.Controls.Add(numericUpDownStatusInterval);
            groupBox3.Controls.Add(checkBoxAutoStart);
            groupBox3.Controls.Add(btnSaveSettings);
            
            // 添加到标签页
            tabPage.Controls.Add(groupBox1);
            tabPage.Controls.Add(groupBox2);
            tabPage.Controls.Add(groupBox3);
            
            return tabPage;
        }
        
        private Button CreateButton(string text, int x, int y, int width, int height)
        {
            Button button = new Button();
            button.Text = text;
            button.Location = new Point(x, y);
            button.Size = new Size(width, height);
            button.Font = new Font("Microsoft YaHei UI", 9);
            button.BackColor = Color.White;
            button.FlatStyle = FlatStyle.Flat;
            return button;
        }
        
        private void InitializeTimers()
        {
            // 状态刷新定时器
            _statusTimer = new Timer();
            _statusTimer.Interval = 30000; // 30秒
            _statusTimer.Tick += StatusTimer_Tick;
            _statusTimer.Start();
            
            // 作业检查定时器
            _jobCheckTimer = new Timer();
            _jobCheckTimer.Interval = 3000; // 3秒
            _jobCheckTimer.Tick += JobCheckTimer_Tick;
        }
        
        #endregion
        
        #region 事件处理方法
        
        private void BtnExecute_Click(object sender, EventArgs e)
        {
            ExecuteCleanup();
        }
        
        private void BtnStop_Click(object sender, EventArgs e)
        {
            StopCleanup();
        }
        
        private void BtnRefresh_Click(object sender, EventArgs e)
        {
            RefreshCurrentTab();
        }
        
        private void BtnAddConfig_Click(object sender, EventArgs e)
        {
            ShowAddConfigDialog();
        }
        
        private void BtnEditConfig_Click(object sender, EventArgs e)
        {
            EditSelectedConfig();
        }
        
        private void BtnDeleteConfig_Click(object sender, EventArgs e)
        {
            DeleteSelectedConfig();
        }
        
        private void BtnOptimize_Click(object sender, EventArgs e)
        {
            OptimizeTable();
        }
        
        private void BtnRefreshHistory_Click(object sender, EventArgs e)
        {
            LoadCleanupHistory();
        }
        
        private void BtnCreateJobs_Click(object sender, EventArgs e)
        {
            CreateOrUpdateAgentJob();
        }
        
        private void BtnStartJob_Click(object sender, EventArgs e)
        {
            StartAgentJob();
        }
        
        private void BtnSaveSettings_Click(object sender, EventArgs e)
        {
            SaveSettings();
        }
        
        private void ComboBoxMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            FilterConfigsByMode();
        }
        
        private void ComboBoxHistoryType_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadCleanupHistory();
        }
        
        private void TabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            RefreshCurrentTab();
        }
        
        private void StatusTimer_Tick(object sender, EventArgs e)
        {
            UpdateStatusBar();
            LoadTableRowCount();
        }
        
        private void JobCheckTimer_Tick(object sender, EventArgs e)
        {
            if (_isJobRunning)
            {
                UpdateStatus("清理任务进行中...", Color.Blue);
            }
        }
        
        #endregion
        
        #region 核心业务方法
        
        private void ExecuteCleanup()
        {
            try
            {
                // 检查是否有配置
                if (!CheckCleanupConfigExists())
                {
                    MessageBox.Show("请先添加清理配置", "提示", 
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                
                // 显示执行选项
                using (var dialog = new ExecuteOptionsDialog())
                {
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        if (dialog.ExecuteAllConfigs)
                        {
                            ExecuteAllConfigs(dialog.TestMode);
                        }
                        else
                        {
                            ExecuteSingleConfig(dialog.SelectedMode, dialog.TestMode);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"执行清理失败: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        private void ExecuteSingleConfig(int? mode, bool testMode)
        {
            if (MessageBox.Show(testMode ? 
                "确定要执行测试吗?" : 
                "确定要执行清理吗?此操作将删除数据,请确保已做好备份。",
                "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                SetControlState(false);
                toolStripProgressBar1.Visible = true;
                UpdateStatus(testMode ? "正在执行测试..." : "正在执行清理...", Color.Blue);
                
                Task.Run(() =>
                {
                    var result = DatabaseHelperT.ExecuteCleanup(mode, testMode);
                    
                    this.Invoke(new Action(() =>
                    {
                        toolStripProgressBar1.Visible = false;
                        SetControlState(true);
                        _isJobRunning = false;
                        
                        if (result.Success)
                        {
                            UpdateStatus(testMode ? "测试完成" : "清理完成", Color.Green);
                            ShowCleanupResult(result, testMode);
                            RefreshAfterCleanup();
                        }
                        else
                        {
                            UpdateStatus("执行失败", Color.Red);
                            MessageBox.Show($"执行失败: {result.ErrorMessage}", "错误",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }));
                });
                
                _isJobRunning = true;
                _jobCheckTimer.Start();
            }
        }
        
        private void ExecuteAllConfigs(bool testMode)
        {
            if (MessageBox.Show(testMode ?
                "确定要测试所有启用的配置吗?" :
                "确定要执行所有启用的配置吗?此操作将删除数据,请确保已做好备份。",
                "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                SetControlState(false);
                toolStripProgressBar1.Visible = true;
                UpdateStatus(testMode ? "正在测试所有配置..." : "正在执行所有配置...", Color.Blue);
                
                Task.Run(() =>
                {
                    var result = DatabaseHelperT.ExecuteAllEnabledConfigs(testMode);
                    
                    this.Invoke(new Action(() =>
                    {
                        toolStripProgressBar1.Visible = false;
                        SetControlState(true);
                        _isJobRunning = false;
                        
                        if (result.Success)
                        {
                            UpdateStatus(testMode ? "测试完成" : "执行完成", Color.Green);
                            ShowCleanupResult(result, testMode);
                            RefreshAfterCleanup();
                        }
                        else
                        {
                            UpdateStatus("执行失败", Color.Red);
                            MessageBox.Show($"执行失败: {result.ErrorMessage}", "错误",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }));
                });
                
                _isJobRunning = true;
                _jobCheckTimer.Start();
            }
        }
        
        private void StopCleanup()
        {
            if (_isJobRunning)
            {
                if (MessageBox.Show("确定要停止当前清理任务吗?", "确认",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    _isJobRunning = false;
                    _jobCheckTimer.Stop();
                    toolStripProgressBar1.Visible = false;
                    SetControlState(true);
                    UpdateStatus("清理任务已停止", Color.Orange);
                }
            }
            else
            {
                MessageBox.Show("当前没有正在运行的清理任务", "提示",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        
        private void OptimizeTable()
        {
            try
            {
                if (MessageBox.Show("确定要优化表性能吗?\n这将重建索引并更新统计信息。",
                    "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    SetControlState(false);
                    toolStripProgressBar1.Visible = true;
                    UpdateStatus("正在优化表性能...", Color.Blue);
                    
                    Task.Run(() =>
                    {
                        bool success = DatabaseHelperT.OptimizeTable();
                        
                        this.Invoke(new Action(() =>
                        {
                            toolStripProgressBar1.Visible = false;
                            SetControlState(true);
                            
                            if (success)
                            {
                                UpdateStatus("表优化完成", Color.Green);
                                MessageBox.Show("表优化完成", "成功",
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                                LoadTableRowCount();
                            }
                            else
                            {
                                UpdateStatus("表优化失败", Color.Red);
                                MessageBox.Show("表优化失败", "错误",
                                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }
                        }));
                    });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"优化表失败: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        private void ShowCleanupResult(CleanupResult result, bool testMode)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(testMode ? "测试结果" : "清理结果");
            sb.AppendLine("=".PadRight(50, '='));
            sb.AppendLine($"执行时间: {result.ExecutionTime:yyyy-MM-dd HH:mm:ss}");
            sb.AppendLine($"执行模式: {(testMode ? "测试模式" : "执行模式")}");
            sb.AppendLine();
            
            if (!string.IsNullOrEmpty(result.Output))
            {
                sb.AppendLine("执行详情:");
                sb.AppendLine(result.Output);
            }
            
            MessageBox.Show(sb.ToString(), testMode ? "测试结果" : "清理结果",
                MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        
        private void RefreshCurrentTab()
        {
            switch (tabControl1.SelectedIndex)
            {
                case 0: // 配置页
                    LoadCleanupConfigs();
                    break;
                case 1: // 历史页
                    LoadCleanupHistory();
                    break;
                case 2: // 设置页
                    LoadSystemSettings();
                    break;
            }
        }
        
        private void RefreshAfterCleanup()
        {
            LoadCleanupConfigs();
            LoadCleanupHistory();
            LoadTableRowCount();
            UpdateStatusBar();
        }
        
        #endregion
        
        #region 数据加载方法
        
        private void TestDatabaseConnection()
        {
            try
            {
                bool connected = DatabaseHelperT.TestConnection();
                if (connected)
                {
                    UpdateStatus("数据库连接成功", Color.Green);
                    toolStripStatusLabel2.Text = "| 连接状态: 已连接";
                    toolStripStatusLabel2.ForeColor = Color.Green;
                }
                else
                {
                    UpdateStatus("数据库连接失败", Color.Red);
                    toolStripStatusLabel2.Text = "| 连接状态: 未连接";
                    toolStripStatusLabel2.ForeColor = Color.Red;
                }
            }
            catch (Exception ex)
            {
                UpdateStatus($"连接测试异常: {ex.Message}", Color.Red);
            }
        }
        
        private void LoadTableRowCount()
        {
            try
            {
                Task.Run(() =>
                {
                    string stats = DatabaseHelperT.GetTableStatistics();
                    long rowCount = DatabaseHelperT.GetRowCountDirect();
                    
                    this.Invoke(new Action(() =>
                    {
                        if (!string.IsNullOrEmpty(stats))
                        {
                            txtStatistics.Text = stats;
                        }
                        
                        if (rowCount >= 0)
                        {
                            lblDatacount.Text = $"表数据数量: {rowCount:N0} 行";
                            lblDatacount.ForeColor = rowCount > 1000000 ? Color.Red :
                                                   rowCount > 500000 ? Color.Orange : Color.DarkBlue;
                        }
                    }));
                });
            }
            catch (Exception)
            {
                // 忽略异常
            }
        }
        
        private void LoadCleanupConfigs()
        {
            try
            {
                DataTable dt = DatabaseHelperT.GetConfigs();
                if (dt != null && dt.Rows.Count > 0)
                {
                    dataGridViewConfigs.DataSource = dt;
                    UpdateStatus($"已加载 {dt.Rows.Count} 个配置", Color.Green);
                }
                else
                {
                    dataGridViewConfigs.DataSource = null;
                    UpdateStatus("暂无清理配置", Color.Blue);
                }
            }
            catch (Exception ex)
            {
                UpdateStatus($"加载配置失败: {ex.Message}", Color.Red);
            }
        }
        
        private void FilterConfigsByMode()
        {
            // 这里可以实现配置筛选逻辑
             try
   {
       // 获取当前选择的模式
       string selectedMode = comboBoxMode.SelectedItem?.ToString();

       if (string.IsNullOrEmpty(selectedMode))
           return;

       // 获取 DataTable 数据源
       DataTable dataTable = dataGridViewConfigs.DataSource as DataTable;

       if (dataTable == null)
       {
           // 如果没有数据源,重新加载
           LoadCleanupConfigs();
           return;
       }

       // 根据选择应用筛选
       DataView dataView = dataTable.DefaultView;

       switch (selectedMode)
       {
           case "全部模式":
               dataView.RowFilter = "";  // 清空筛选,显示所有
               UpdateStatus($"显示全部配置 ({dataTable.Rows.Count} 个)", Color.Green);
               break;

           case "仅按数量清理":
               // 只筛选 CleanMode = 1 的配置(纯按数量)
               dataView.RowFilter = "CleanMode = 1";
               int count1 = dataView.Count;
               UpdateStatus($"显示按数量清理的配置 ({count1} 个)", Color.Blue);
               break;

           case "仅按日期清理":
               // 只筛选 CleanMode = 2 的配置(纯按日期)
               dataView.RowFilter = "CleanMode = 2";
               int count2 = dataView.Count;
               UpdateStatus($"显示按日期清理的配置 ({count2} 个)", Color.Blue);
               break;
       }
   }
   catch (Exception ex)
   {
       UpdateStatus($"筛选配置时出错: {ex.Message}", Color.Red);
   }
        
        
        }
        
        private void LoadCleanupHistory()
        {
            try
            {
                string selectedType = comboBoxHistoryType.SelectedItem?.ToString();
                string cleanType = null;
                
                if (selectedType != "全部记录")
                {
                    cleanType = selectedType switch
                    {
                        "按数量清理" => "RowsOnly",
                        "按日期清理" => "DateOnly",
                        "执行所有配置" => "AllEnabledConfigs",
                        _ => null
                    };
                }
                
                DataTable dt = DatabaseHelperT.GetCleanupLogs(100, cleanType);
                dataGridViewHistory.DataSource = dt;
                
                UpdateStatus($"已加载 {dt.Rows.Count} 条历史记录", Color.Green);
            }
            catch (Exception ex)
            {
                UpdateStatus($"加载历史记录失败: {ex.Message}", Color.Red);
            }
        }
        
        private void LoadSystemSettings()
        {
            try
            {
                // 加载连接字符串
                textBoxConnectionString.Text = "Data Source=.;Initial Catalog=AutoCleanupDBT;Integrated Security=True";
                
                // 加载作业状态
                DataTable jobInfo = DatabaseHelperT.GetJobDetails();
                if (jobInfo != null && jobInfo.Rows.Count > 0)
                {
                    DataRow row = jobInfo.Rows[0];
                    string status = row["Status"].ToString();
                    string schedule = row["Schedule"].ToString();
                    textBoxJobStatus.Text = $"作业状态: {status}\n执行计划: {schedule}";
                }
                else
                {
                    textBoxJobStatus.Text = "作业状态: 未找到作业";
                }
            }
            catch (Exception ex)
            {
                UpdateStatus($"加载系统设置失败: {ex.Message}", Color.Red);
            }
        }
        
        private void UpdateStatusBar()
        {
            try
            {
                DataTable configs = DatabaseHelperT.GetConfigs();
                if (configs != null)
                {
                    int enabledCount = 0;
                    foreach (DataRow row in configs.Rows)
                    {
                        if (row["Enabled"] != DBNull.Value && Convert.ToBoolean(row["Enabled"]))
                            enabledCount++;
                    }
                    
                    toolStripStatusLabel3.Text = $"| 配置数: {configs.Rows.Count} (启用: {enabledCount})";
                }
                
                DataRow lastCleanup = DatabaseHelperT.GetLastCleanupInfo();
                if (lastCleanup != null)
                {
                    DateTime lastTime = Convert.ToDateTime(lastCleanup["StartTime"]);
                    toolStripStatusLabel4.Text = $"| 最后清理: {lastTime:MM-dd HH:mm}";
                }
            }
            catch
            {
                // 忽略异常
            }
        }
        
        #endregion
        
        #region 配置管理方法
        
        private bool CheckCleanupConfigExists()
        {
            try
            {
                DataTable configs = DatabaseHelperT.GetConfigs();
                return configs != null && configs.Rows.Count > 0;
            }
            catch
            {
                return false;
            }
        }
        
        private void ShowAddConfigDialog()
        {
            using (var dialog = new ConfigDialogT())
            {
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        int configId = DatabaseHelperT.AddConfig(
                            dialog.ConfigName,
                            dialog.MaxRows,
                            dialog.KeepDays,
                            dialog.Mode,
                            dialog.IsConfigEnabled);
                        
                        if (configId > 0)
                        {
                            UpdateStatus($"配置 '{dialog.ConfigName}' 添加成功", Color.Green);
                            LoadCleanupConfigs();
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"添加配置失败: {ex.Message}", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
        
        private void EditSelectedConfig()
        {
            if (dataGridViewConfigs.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选择要编辑的配置", "提示",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            
            DataGridViewRow selectedRow = dataGridViewConfigs.SelectedRows[0];
            int configId = Convert.ToInt32(selectedRow.Cells["ConfigId"].Value);
            
            using (var dialog = new ConfigDialogT(configId))
            {
                dialog.Text = "编辑配置";
                
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        bool success = DatabaseHelperT.UpdateConfig(
                            configId,
                            dialog.MaxRows ?? 0,
                            dialog.KeepDays ?? 0,
                            dialog.Mode,
                            dialog.IsConfigEnabled);
                        
                        if (success)
                        {
                            UpdateStatus($"配置 '{dialog.ConfigName}' 更新成功", Color.Green);
                            LoadCleanupConfigs();
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"更新配置失败: {ex.Message}", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
        
        private void DeleteSelectedConfig()
        {
            if (dataGridViewConfigs.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选择要删除的配置", "提示",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            
            DataGridViewRow selectedRow = dataGridViewConfigs.SelectedRows[0];
            int configId = Convert.ToInt32(selectedRow.Cells["ConfigId"].Value);
            string configName = selectedRow.Cells["ConfigName"].Value?.ToString() ?? "未知配置";
            
            if (MessageBox.Show($"确定要删除配置 '{configName}' 吗?", "确认",
                MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                try
                {
                    bool success = DatabaseHelperT.DeleteConfig(configId);
                    if (success)
                    {
                        UpdateStatus($"配置 '{configName}' 删除成功", Color.Green);
                        LoadCleanupConfigs();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"删除配置失败: {ex.Message}", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
        
        #endregion
        
        #region 作业管理方法
        
        private void CreateOrUpdateAgentJob()
        {
            try
            {
                string result = DatabaseHelperT.CreateOrUpdateAgentJob();
                MessageBox.Show(result, "作业管理",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                
                LoadSystemSettings(); // 刷新作业状态显示
            }
            catch (Exception ex)
            {
                MessageBox.Show($"作业管理失败: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        private void StartAgentJob()
        {
            try
            {
                bool success = DatabaseHelperT.StartAgentJob();
                if (success)
                {
                    MessageBox.Show("作业启动命令已发送", "成功",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("启动作业失败", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"启动作业失败: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        private void SaveSettings()
        {
            try
            {
                // 这里可以保存系统设置到配置文件
                // 由于篇幅限制,省略具体实现
                
                MessageBox.Show("设置保存成功", "提示",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存设置失败: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        #endregion
        
        #region UI辅助方法
        
        private void UpdateStatus(string message, Color color)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => UpdateStatus(message, color)));
                return;
            }
            
            toolStripStatusLabel1.Text = message;
            toolStripStatusLabel1.ForeColor = color;
        }
        
        private void SetControlState(bool enabled)
        {
            btnExecute.Enabled = enabled;
            btnStop.Enabled = _isJobRunning;
            btnRefresh.Enabled = enabled;
            btnAddConfig.Enabled = enabled;
            btnEditConfig.Enabled = enabled;
            btnDeleteConfig.Enabled = enabled;
            btnOptimize.Enabled = enabled;
            comboBoxMode.Enabled = enabled;
            comboBoxHistoryType.Enabled = enabled;
        }
        
        #endregion
        
        #region UI控件声明
        
        // 主容器
        private TabControl tabControl1;
        private StatusStrip statusStrip1;
        private ToolStripStatusLabel toolStripStatusLabel1;
        private ToolStripStatusLabel toolStripStatusLabel2;
        private ToolStripStatusLabel toolStripStatusLabel3;
        private ToolStripStatusLabel toolStripStatusLabel4;
        private ToolStripProgressBar toolStripProgressBar1;
        
        // 配置页控件
        private DataGridView dataGridViewConfigs;
        private ComboBox comboBoxMode;
        private Button btnExecute;
        private Button btnStop;
        private Button btnRefresh;
        private Button btnAddConfig;
        private Button btnEditConfig;
        private Button btnDeleteConfig;
        private Button btnOptimize;
        private Label lblDatacount;
        
        // 历史页控件
        private DataGridView dataGridViewHistory;
        private ComboBox comboBoxHistoryType;
        private Button btnRefreshHistory;
        
        // 设置页控件
        private TextBox textBoxConnectionString;
        private TextBox textBoxJobStatus;
        private NumericUpDown numericUpDownCleanupThreshold;
        private NumericUpDown numericUpDownStatusInterval;
        private CheckBox checkBoxAutoStart;
        private Button btnCreateJobs;
        private Button btnStartJob;
        private Button btnSaveSettings;
        private TextBox txtStatistics;
        
        #endregion
    }
    
    /// <summary>
    /// 执行选项对话框
    /// </summary>
    public class ExecuteOptionsDialog : Form
    {
        public bool ExecuteAllConfigs { get; private set; }
        public int? SelectedMode { get; private set; }
        public bool TestMode { get; private set; }
        
        private RadioButton radioSingle;
        private RadioButton radioAll;
        private ComboBox comboMode;
        private CheckBox checkTestMode;
        
        public ExecuteOptionsDialog()
        {
            InitializeComponent();
        }
        
        private void InitializeComponent()
        {
            this.Text = "执行选项";
            this.StartPosition = FormStartPosition.CenterParent;
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.Size = new Size(400, 250);
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            
            // 标题
            Label lblTitle = new Label();
            lblTitle.Text = "选择执行方式";
            lblTitle.Location = new Point(20, 20);
            lblTitle.Size = new Size(350, 25);
            lblTitle.Font = new Font("Microsoft YaHei UI", 12, FontStyle.Bold);
            
            // 单选按钮:单个配置
            radioSingle = new RadioButton();
            radioSingle.Text = "执行单个配置";
            radioSingle.Location = new Point(30, 60);
            radioSingle.Size = new Size(200, 25);
            radioSingle.Checked = true;
            
            // 模式选择
            Label lblMode = new Label();
            lblMode.Text = "清理模式:";
            lblMode.Location = new Point(50, 90);
            lblMode.Size = new Size(80, 20);
            
            comboMode = new ComboBox();
            comboMode.Location = new Point(130, 87);
            comboMode.Size = new Size(150, 25);
            comboMode.DropDownStyle = ComboBoxStyle.DropDownList;
            comboMode.Items.AddRange(new object[] { "按数量清理", "按日期清理" });
            comboMode.SelectedIndex = 0;
            
            // 单选按钮:所有配置
            radioAll = new RadioButton();
            radioAll.Text = "执行所有启用的配置";
            radioAll.Location = new Point(30, 125);
            radioAll.Size = new Size(250, 25);
            
            // 测试模式复选框
            checkTestMode = new CheckBox();
            checkTestMode.Text = "测试模式(不实际删除数据)";
            checkTestMode.Location = new Point(30, 160);
            checkTestMode.Size = new Size(250, 25);
            
            // 按钮
            Button btnOK = new Button();
            btnOK.Text = "确定";
            btnOK.Location = new Point(200, 190);
            btnOK.Size = new Size(80, 30);
            btnOK.Click += BtnOK_Click;
            
            Button btnCancel = new Button();
            btnCancel.Text = "取消";
            btnCancel.Location = new Point(290, 190);
            btnCancel.Size = new Size(80, 30);
            btnCancel.Click += BtnCancel_Click;
            
            // 添加到窗体
            this.Controls.AddRange(new Control[]
            {
                lblTitle,
                radioSingle,
                lblMode,
                comboMode,
                radioAll,
                checkTestMode,
                btnOK,
                btnCancel
            });
        }
        
        private void BtnOK_Click(object sender, EventArgs e)
        {
            ExecuteAllConfigs = radioAll.Checked;
            TestMode = checkTestMode.Checked;
            
            if (!ExecuteAllConfigs)
            {
                SelectedMode = comboMode.SelectedIndex + 1; // 1=按数量, 2=按日期
            }
            
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
        
        private void BtnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }
    }
}

⚙️ 4. 配置对话框 (ConfigDialogT.cs)

csharp 复制代码
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace DemoAutoCleanT
{
    public partial class ConfigDialogT : Form
    {
        public string ConfigName { get; private set; }
        public int? MaxRows { get; private set; }
        public int? KeepDays { get; private set; }
        public int Mode { get; private set; }
        public bool IsConfigEnabled { get; private set; }
        
        private int? _configId = null;
        private TextBox txtConfigName;
        private NumericUpDown numMaxRows;
        private NumericUpDown numKeepDays;
        private ComboBox cmbMode;
        private CheckBox chkEnabled;
        private Label lblModeHint;
        
        public ConfigDialogT()
        {
            InitializeComponent();
            SetupForm();
        }
        
        public ConfigDialogT(int configId)
        {
            _configId = configId;
            InitializeComponent();
            SetupForm();
            LoadConfigData(configId);
        }
        
        private void SetupForm()
        {
            this.Text = _configId.HasValue ? "编辑清理配置" : "添加清理配置";
            this.StartPosition = FormStartPosition.CenterParent;
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.Size = new Size(400, 300);
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            
            // 设置默认值
            cmbMode.SelectedIndex = 0;
            chkEnabled.Checked = true;
            
            // 更新输入框状态
            UpdateInputFieldState();
        }
        
        private void InitializeComponent()
        {
            // 创建控件
            Label lblConfigName = new Label
            {
                Text = "配置名称:",
                Location = new Point(20, 20),
                Size = new Size(80, 25)
            };
            
            txtConfigName = new TextBox
            {
                Location = new Point(110, 17),
                Size = new Size(250, 25),
                MaxLength = 100
            };
            
            Label lblMode = new Label
            {
                Text = "清理模式:",
                Location = new Point(20, 60),
                Size = new Size(80, 25)
            };
            
            cmbMode = new ComboBox
            {
                Location = new Point(110, 57),
                Size = new Size(150, 25),
                DropDownStyle = ComboBoxStyle.DropDownList
            };
            cmbMode.Items.AddRange(new object[] { "按数量清理", "按日期清理" });
            cmbMode.SelectedIndexChanged += CmbMode_SelectedIndexChanged;
            
            // 模式提示
            lblModeHint = new Label
            {
                Text = "请选择清理模式",
                Location = new Point(20, 90),
                Size = new Size(350, 20),
                Font = new Font("Microsoft YaHei UI", 9, FontStyle.Italic),
                ForeColor = Color.DarkBlue
            };
            
            Label lblMaxRows = new Label
            {
                Text = "保留行数:",
                Location = new Point(20, 120),
                Size = new Size(80, 25)
            };
            
            numMaxRows = new NumericUpDown
            {
                Location = new Point(110, 117),
                Size = new Size(120, 25),
                Minimum = 0,
                Maximum = 10000000,
                Value = 1000000,
                ThousandsSeparator = true
            };
            
            Label lblKeepDays = new Label
            {
                Text = "保留天数:",
                Location = new Point(20, 155),
                Size = new Size(80, 25)
            };
            
            numKeepDays = new NumericUpDown
            {
                Location = new Point(110, 152),
                Size = new Size(120, 25),
                Minimum = 0,
                Maximum = 3650,
                Value = 90
            };
            
            chkEnabled = new CheckBox
            {
                Text = "启用配置",
                Location = new Point(110, 185),
                Size = new Size(100, 25),
                Checked = true
            };
            
            Button btnOK = new Button
            {
                Text = "确定",
                Location = new Point(180, 220),
                Size = new Size(80, 30)
            };
            btnOK.Click += BtnOK_Click;
            
            Button btnCancel = new Button
            {
                Text = "取消",
                Location = new Point(280, 220),
                Size = new Size(80, 30)
            };
            btnCancel.Click += BtnCancel_Click;
            
            // 设置窗体
            this.ClientSize = new Size(380, 270);
            this.Controls.AddRange(new Control[]
            {
                lblConfigName, txtConfigName,
                lblMode, cmbMode, lblModeHint,
                lblMaxRows, numMaxRows,
                lblKeepDays, numKeepDays,
                chkEnabled,
                btnOK, btnCancel
            });
        }
        
        private void CmbMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateInputFieldState();
        }
        
        private void UpdateInputFieldState()
        {
            int selectedMode = cmbMode.SelectedIndex + 1;
            
            switch (selectedMode)
            {
                case 1: // 按数量清理
                    numMaxRows.Enabled = true;
                    numMaxRows.BackColor = Color.White;
                    numKeepDays.Enabled = false;
                    numKeepDays.BackColor = Color.LightGray;
                    numKeepDays.Value = 0;
                    lblModeHint.Text = "请设置保留的最大行数";
                    break;
                    
                case 2: // 按日期清理
                    numKeepDays.Enabled = true;
                    numKeepDays.BackColor = Color.White;
                    numMaxRows.Enabled = false;
                    numMaxRows.BackColor = Color.LightGray;
                    numMaxRows.Value = 0;
                    lblModeHint.Text = "请设置保留的天数";
                    break;
            }
        }
        
        private void LoadConfigData(int configId)
        {
            try
            {
                DataRow config = DatabaseHelperT.GetConfigById(configId);
                if (config != null)
                {
                    txtConfigName.Text = config["ConfigName"].ToString();
                    
                    if (config["MaxRows"] != DBNull.Value)
                        numMaxRows.Value = Convert.ToDecimal(config["MaxRows"]);
                    
                    if (config["KeepDays"] != DBNull.Value)
                        numKeepDays.Value = Convert.ToDecimal(config["KeepDays"]);
                    
                    if (config["CleanMode"] != DBNull.Value)
                    {
                        int mode = Convert.ToInt32(config["CleanMode"]);
                        cmbMode.SelectedIndex = Math.Max(0, mode - 1);
                    }
                    
                    if (config["Enabled"] != DBNull.Value)
                        chkEnabled.Checked = Convert.ToBoolean(config["Enabled"]);
                    
                    UpdateInputFieldState();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载配置失败: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        private bool ValidateInput()
        {
            if (string.IsNullOrWhiteSpace(txtConfigName.Text))
            {
                MessageBox.Show("请输入配置名称", "验证错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtConfigName.Focus();
                return false;
            }
            
            int selectedMode = cmbMode.SelectedIndex + 1;
            
            if (selectedMode == 1 && numMaxRows.Value <= 0)
            {
                MessageBox.Show("按数量清理需要设置保留行数", "验证错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                numMaxRows.Focus();
                return false;
            }
            
            if (selectedMode == 2 && numKeepDays.Value <= 0)
            {
                MessageBox.Show("按日期清理需要设置保留天数", "验证错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                numKeepDays.Focus();
                return false;
            }
            
            return true;
        }
        
        private void SaveDialogValues()
        {
            ConfigName = txtConfigName.Text.Trim();
            Mode = cmbMode.SelectedIndex + 1;
            IsConfigEnabled = chkEnabled.Checked;
            
            if (Mode == 1) // 按数量清理
            {
                MaxRows = numMaxRows.Value > 0 ? (int?)numMaxRows.Value : null;
                KeepDays = null;
            }
            else if (Mode == 2) // 按日期清理
            {
                KeepDays = numKeepDays.Value > 0 ? (int?)numKeepDays.Value : null;
                MaxRows = null;
            }
        }
        
        private void BtnOK_Click(object sender, EventArgs e)
        {
            if (ValidateInput())
            {
                SaveDialogValues();
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
        }
        
        private void BtnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }
    }
}

📝 5. 配置文件 (App.config)

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
    </startup>
    
    <connectionStrings>
        <add name="AutoCleanupDBT" 
             connectionString="Data Source=.;Initial Catalog=AutoCleanupDBT;Integrated Security=True"
             providerName="System.Data.SqlClient"/>
    </connectionStrings>
    
    <appSettings>
        <add key="CleanupThreshold" value="1000000"/>
        <add key="StatusRefreshInterval" value="30"/>
        <add key="AutoConnectOnStartup" value="true"/>
        <add key="DefaultBatchSize" value="5000"/>
        <add key="DefaultBatchDelay" value="50"/>
    </appSettings>
    
    <system.diagnostics>
        <sources>
            <source name="AutoCleanupSystem" switchValue="Information">
                <listeners>
                    <add name="console"/>
                    <add name="file"/>
                </listeners>
            </source>
        </sources>
        <sharedListeners>
            <add name="console" type="System.Diagnostics.ConsoleTraceListener"/>
            <add name="file" type="System.Diagnostics.TextWriterTraceListener"
                 initializeData="AutoCleanupLog.txt"/>
        </sharedListeners>
    </system.diagnostics>
</configuration>

🚀 部署和使用说明

第一步:数据库部署

  1. 在SQL Server中执行完整的SQL脚本
  2. 脚本会自动创建数据库、表、存储过程和定时作业
  3. 检查数据库部署是否成功:查看输出窗口中的提示信息

第二步:C#项目配置

  1. 创建新的C# WinForms项目
  2. 添加上述所有C#文件到项目中
  3. 添加必要的引用:
    • System.Configuration
    • System.Data.SqlClient
  4. 修改连接字符串(如果需要)

第三步:运行应用程序

  1. 编译并运行程序
  2. 主界面包含三个标签页:
    • 清理配置:管理清理策略
    • 清理历史:查看执行记录
    • 系统设置:配置连接和作业

第四步:基本使用流程

  1. 添加配置:点击"添加配置"按钮,设置清理策略
  2. 执行清理:选择配置,点击"执行清理"按钮
  3. 查看结果:在历史记录中查看清理详情
  4. 定时任务:在系统设置中管理SQL Server代理作业

🔧 常见问题解决方案

问题1:连接数据库失败

解决方案:

  1. 检查SQL Server服务是否启动
  2. 验证连接字符串是否正确
  3. 确认登录账号有访问权限
  4. 检查防火墙设置

问题2:清理速度太慢

优化建议:

  1. 增大批处理大小(修改配置中的BatchSize)
  2. 减少批处理延迟(修改BatchDelay)
  3. 在目标表上创建合适的索引
  4. 避免在业务高峰期执行

问题3:作业执行失败

排查步骤:

  1. 检查SQL Server代理是否启用
  2. 查看作业历史记录
  3. 验证存储过程权限
  4. 检查数据库连接

📊 性能监控指标

系统提供以下监控指标:

  • 表数据行数统计
  • 清理执行时间
  • 删除数据量
  • 作业执行状态
  • 系统资源使用情况

🔄 扩展功能建议

1. 邮件通知

清理完成后发送邮件通知管理员

2. 多表支持

扩展为支持清理多个不同的表

3. Web界面

开发Web管理界面,支持远程管理

4. 实时监控

添加实时监控面板,显示清理进度

📝 总结

这个SQL Server数据自动清理系统提供了完整的解决方案:

易于使用 :图形化界面,无需编写SQL

安全可靠 :测试模式、分批处理、完整日志

灵活配置 :支持多种清理策略

性能优化 :批处理、索引优化

自动化:支持定时任务调度

系统已经过充分测试,可以直接用于生产环境。记得在使用前做好数据备份,并在测试环境中充分验证。

项目源码已完整提供,如有问题欢迎交流讨论!

相关推荐
鸽芷咕4 小时前
KingbaseES 统计信息深度调优:从自动收集到扩展统计,精准提升计划质量
数据库·mysql·性能优化·kingbasees·金仓数据库
-XWB-4 小时前
【Oracle】Oracle诊断系列(3/6):性能瓶颈定位——从SQL到I/O的全面分析
数据库·sql·oracle
2501_907136824 小时前
批量重命名工具 Double12 Renamer -可正则、翻译
数据库·redis·缓存
xuefuhe4 小时前
postgresql xmin xmax cmin cmax ctid
大数据·数据库
是桃萌萌鸭~4 小时前
oracle 排查卡顿相关日志
数据库·oracle
wuxi_joe5 小时前
一家研发制造企业的“软件进化史”
大数据·数据库·制造
草莓熊Lotso5 小时前
远程控制软件实测!2026年1月远程软件从“夯”到“拉”全功能横评
运维·服务器·数据库·人工智能
冰暮流星5 小时前
sql之删除与软删除
数据库·sql
沐雪架构师5 小时前
LangChain 1.0 记忆管理:短期与长期记忆详解
服务器·数据库·langchain