SqlSugar高效批量删除

在实际应用开发中,批量删除操作是常见的数据库操作需求。SqlSugar提供了多种高效的批量删除方案,本文将全面解析各种方法的性能特点、适用场景和最佳实践。

1. 基础批量删除方法

1.1 根据主键批量删除

// 方法1:使用主键列表直接删除
var ids = new[] { 1, 2, 3, 4, 5 };
var result = db.Deleteable<Order>().In(ids).ExecuteCommand();

// 方法2:使用实体列表删除(基于主键)
var orders = GetOrdersToDelete();
var result = db.Deleteable(orders).ExecuteCommand();

// 异步版本
var result = await db.Deleteable<Order>().In(ids).ExecuteCommandAsync();

1.2 根据条件批量删除

// 根据条件删除数据
var result = db.Deleteable<Order>()
    .Where(o => o.Status == OrderStatus.Deleted)
    .ExecuteCommand();

// 复杂条件删除
var result = db.Deleteable<Order>()
    .Where(o => o.CreateTime < DateTime.Now.AddYears(-1) && o.Amount < 100)
    .ExecuteCommand();

2. 高性能批量删除方案

2.1 分页批量删除(大数据量推荐

public async Task<long> BatchDeleteInPages<T>(Expression<Func<T, bool>> whereExpression, int pageSize = 1000) where T : class, new()
{
    var totalDeleted = 0L;
    var hasMoreData = true;
    var pageIndex = 0;

    while (hasMoreData)
    {
        try
        {
            // 先查询要删除的ID(避免表锁)
            var idsToDelete = await db.Queryable<T>()
                .Where(whereExpression)
                .OrderBy("Id")  // 确保排序一致性
                .Select("Id")   // 只查询ID字段
                .Skip(pageIndex * pageSize)
                .Take(pageSize)
                .SelectColumns("Id")
                .ToListAsync();

            if (!idsToDelete.Any())
            {
                hasMoreData = false;
                break;
            }

            var idList = idsToDelete.Select(x => (x as dynamic).Id).ToList();
            
            // 执行批量删除
            var deletedCount = await db.Deleteable<T>()
                .In(idList)
                .ExecuteCommandAsync();

            totalDeleted += deletedCount;
            pageIndex++;

            // 避免数据库压力过大,适当延迟
            if (hasMoreData)
                await Task.Delay(100);
                
            Console.WriteLine($"已删除 {totalDeleted} 条记录...");
        }
        catch (Exception ex)
        {
            // 记录日志并继续
            Console.WriteLine($"第{pageIndex + 1}页删除失败: {ex.Message}");
            break;
        }
    }

    return totalDeleted;
}

// 使用示例
var deletedCount = await BatchDeleteInPages<Order>(o => 
    o.CreateTime < DateTime.Now.AddYears(-1) && o.Status == OrderStatus.Completed);

2.2 使用存储过程批量删除

// 创建批量删除存储过程
public async Task<int> BulkDeleteWithProcedure(string tableName, DateTime deleteBefore)
{
    var parameters = new[]
    {
        new SugarParameter("@TableName", tableName),
        new SugarParameter("@DeleteBefore", deleteBefore),
        new SugarParameter("@DeletedCount", 0, true) // 输出参数
    };

    await db.Ado.UseStoredProcedure().ExecuteCommandAsync(
        "usp_BatchDeleteOldData", parameters);

    return Convert.ToInt32(parameters[2].Value);
}

// 对应的SQL Server存储过程示例
/*
CREATE PROCEDURE usp_BatchDeleteOldData
    @TableName NVARCHAR(100),
    @DeleteBefore DATETIME,
    @DeletedCount INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @Sql NVARCHAR(1000);
    SET @Sql = N'DELETE FROM ' + @TableName + 
               N' WHERE CreateTime < @DeleteBefore';
    
    EXEC sp_executesql @Sql, 
         N'@DeleteBefore DATETIME, @DeletedCount INT OUTPUT',
         @DeleteBefore, @DeletedCount OUTPUT;
END
*/

3. 高级批量删除技巧

3.1 带事务的级联删除

public async Task<bool> BatchDeleteWithTransaction<T>(List<long> ids) where T : class, new()
{
    try
    {
        db.Ado.BeginTran();
        
        // 1. 先删除关联表数据
        await db.Deleteable<OrderDetail>()
            .Where(od => ids.Contains(od.OrderId))
            .ExecuteCommandAsync();
            
        // 2. 再删除主表数据
        await db.Deleteable<T>()
            .In(ids)
            .ExecuteCommandAsync();
            
        // 3. 记录删除日志
        await db.Insertable(ids.Select(id => new DeleteLog
        {
            TableName = typeof(T).Name,
            RecordId = id,
            DeleteTime = DateTime.Now
        }).ToList()).ExecuteCommandAsync();

        db.Ado.CommitTran();
        return true;
    }
    catch (Exception ex)
    {
        db.Ado.RollbackTran();
        _logger.LogError(ex, "批量删除事务失败");
        return false;
    }
}

3.2 软删除实现

// 实体类定义软删除
public class Order : ISoftDelete
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public long Id { get; set; }
    
    public string OrderNo { get; set; }
    
    [SugarColumn(IsSoftDelete = true)]  // 软删除标记
    public bool IsDeleted { get; set; }
    
    public DateTime? DeleteTime { get; set; }
}

// 批量软删除
public async Task<int> SoftBatchDelete<T>(List<long> ids) where T : class, ISoftDelete, new()
{
    return await db.Updateable<T>()
        .SetColumns(t => new T 
        { 
            IsDeleted = true,
            DeleteTime = DateTime.Now
        })
        .Where(t => ids.Contains(t.Id))
        .ExecuteCommandAsync();
}

4. 性能优化策略

4.1 删除条件优化

public async Task<int> OptimizedBatchDelete<T>(Expression<Func<T, bool>> condition) where T : class, new()
{
    // 方法1:使用索引字段作为删除条件
    var result = await db.Deleteable<T>()
        .Where(condition)
        .ExecuteCommandAsync();
        
    return result;
}

// 推荐的删除条件(使用索引字段)
public async Task CleanOldData()
{
    // 好的实践:使用索引字段
    await db.Deleteable<Order>()
        .Where(o => o.CreateTime < DateTime.Now.AddMonths(-6))  // CreateTime应该有索引
        .ExecuteCommandAsync();
        
    // 避免的实践:使用非索引字段
    // await db.Deleteable<Order>()
    //     .Where(o => o.Description.Contains("test"))  // Description可能没有索引
    //     .ExecuteCommandAsync();
}

4.2 批量删除参数调优

public class BatchDeleteConfig
{
    public int BatchSize { get; set; } = 1000;
    public int TimeoutSeconds { get; set; } = 300;
    public int DelayMilliseconds { get; set; } = 100;
}

public async Task<BatchDeleteResult> OptimizedBatchDelete<T>(
    Expression<Func<T, bool>> condition, 
    BatchDeleteConfig config = null) where T : class, new()
{
    config ??= new BatchDeleteConfig();
    var result = new BatchDeleteResult();
    
    db.Ado.CommandTimeOut = config.TimeoutSeconds;
    
    var stopwatch = Stopwatch.StartNew();
    
    try
    {
        // 获取总记录数
        result.TotalRecords = await db.Queryable<T>()
            .Where(condition)
            .CountAsync();
            
        // 分页删除
        result.DeletedCount = await BatchDeleteInPages(condition, config.BatchSize);
        
        stopwatch.Stop();
        result.ElapsedMilliseconds = stopwatch.ElapsedMilliseconds;
    }
    catch (Exception ex)
    {
        result.Error = ex.Message;
    }
    
    return result;
}

SqlSugar批量删除的最佳实践建议:

  1. 小数据量(千条以内):使用直接条件删除

  2. 中等数据量(千条到十万条):使用分页批量删除

  3. 大数据量(十万条以上):使用存储过程或分批次处理

  4. 关键数据:实施软删除或先备份再删除

  5. 生产环境:添加完善的监控和日志记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code_shenbing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值