C#使用SQLBulkCopy或等效库有效地批量删除50000条记录

时间:2019-01-28 14:21:08

标签: c# asp.net asp.net-mvc bulk bulk-delete

我正在使用该库来批量执行批量删除,如下所示:

  while (castedEndedItems.Any())
  {
    var subList = castedEndedItems.Take(4000).ToList();
    DBRetry.Do(() => EFBatchOperation.For(ctx, ctx.SearchedUserItems).Where(r => subList.Any(a => a == r.ItemID)).Delete(), TimeSpan.FromSeconds(2));
    castedEndedItems.RemoveRange(0, subList.Count);
    Console.WriteLine("Completed a batch of ended items");
  }

您可以看到,我一次要删除4000批商品,并将它们作为参数传递给查询...

我正在使用此库执行批量删除:

https://github.com/MikaelEliasson/EntityFramework.Utilities

但是这样的性能是绝对糟糕的...我测试了几次应用程序并删除了80000条记录,例如,这实际上需要40分钟!?

我应该注意,我要用来删除(ItemID)的参数属于varchar(400)类型,并且出于性能原因而对其进行了索引。...

是否还有其他我可以使用或调整此查询的库以使其运行更快,因为当前的性能绝对糟糕。.::

3 个答案:

答案 0 :(得分:4)

如果准备使用存储过程,则可以在没有任何外部库的情况下执行此操作:

  • 使用表值参数@ids创建存储过程
  • 为该表值参数(仅假设一个简单的PK为id列)定义SQL类型
  • 在存储过程中使用

    delete from table where id in (select id from @ids);
    
  • 在您的应用程序中创建一个DataTable并填充以匹配SQL表

  • 在调用sproc时将数据表作为命令参数传递。

This answer说明了该过程。

任何其他选择都需要做到这一点–或效率较低。

答案 1 :(得分:2)

这里的任何EF解决方案都可能执行很多谨慎操作。相反,我建议手动在循环中构建SQL,例如:

using(var cmd = db.CreateCommand())
{
    int index = 0;
    var sql = new StringBuilder("delete from [SomeTable] where [SomeId] in (");
    foreach(var item in items)
    {
        if (index != 0) sql.Append(',');
        var name = "@id_" + index++;
        sql.Append(name);
        cmd.Parameters.AddWithValue(name, item.SomeId);            
    }
    cmd.CommandText = sql.Append(");").ToString();
    cmd.ExecuteNonQuery();
}

但是,由于命令上允许的参数数量有上限,因此您可能需要分批循环 this

答案 2 :(得分:2)

如果您不介意额外的依赖关系,则可以使用NuGet包Z.EntityFramework.Plus。

代码大致如下:

using Z.EntityFramework.Plus;
[...]
         using (yourDbContext context = new yourDbContext())
         {
              yourDbContext.yourDbSet.Where( yourWhereExpression ).Delete();
         }

简单高效。 documentation包含有关效果的确切数字。

关于许可:据我所知,版本1.8具有MIT许可:https://github.com/zzzprojects/EntityFramework-Plus/blob/master/LICENSE 较新的版本不能免费使用。