【问题标题】:Fastest way of performing Bulk Update in C# / .NET在 C# / .NET 中执行批量更新的最快方法
【发布时间】:2017-10-25 06:43:02
【问题描述】:

我正在尝试找出通过 SQL Server 中的迷你控制台应用程序执行批量更新的最佳方法。我已经编写了自己的批量更新方式,如下所示:

  SqlCommand command = new SqlCommand();
  command.Connection = new SqlConnection("Data Source=.;Initial Catalog=mydb;Integrated Security=SSPI");
  command.Connection.Open();

  for (int i = 0; i < items.Count; i = i + 1000)
  {
     var batchList = items.Skip(i).Take(1000).ToList();
     for (int j = 0; j < batchList.Count(); j++)
     {
       command.CommandText += string.Format("update Items set QuantitySold=@s_id{0} where ItemID = @id{0};", j);
       command.Parameters.AddWithValue("@s_id" + j, batchList[j].QuantitySold);
       command.Parameters.AddWithValue("@id" + j, batchList[j].ItemID);
      }
     command.ExecuteNonQuery();
     command = new SqlCommand();
     command.Connection = new SqlConnection("Data Source=.;Initial Catalog=mydb;Integrated Security=SSPI");
     command.Connection.Open();
            }
     command.Connection.Close();

但是我对这个性能不太满意,更新我的数据库中的 50000-100000 条记录时,这样做会变得很慢,即使它以 1000 条为单位进行更新......

是否有任何可以“加快速度”的库/解决方案?

有人可以帮帮我吗?

【问题讨论】:

  • 如果您创建基于集合的更新而不是为每一行单独更新,这会快很多。我会考虑创建一个表参数并将其移至存储过程。
  • 在您的数据库中创建一个队列并将记录转储到其中,让数据库进程更新数据。插入物既便宜又快速。
  • @SeanLange 你能以回答的形式回复,以便我能明白你的意思吗? =)
  • 设置更新是要走的路,但是速度慢的另一个原因是因为你一直在打开和关闭连接,而且没有必要这样做,在一个上进行。
  • 而且,您不需要不断地创建不同数字的参数。设置您的命令对象一次,然后只需不断更改参数(不是名称)的值以保持传递更新。

标签: c# sql-server performance c#-4.0 bulkupdate


【解决方案1】:

最快的方法是使用内置的SqlBulkCopy 类将bulk insert 数据放入临时表中,然后update using join to that table

或者您可以使用诸如SqlBulkTools 之类的工具,它可以轻松完成此操作。

var bulk = new BulkOperations();

using (TransactionScope trans = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=mydb;Integrated Security=SSPI")
    {
        bulk.Setup()
            .ForCollection(items)
            .WithTable("Items")
            .AddColumn(x => x.QuantitySold)
            .BulkUpdate()
            .MatchTargetOn(x => x.ItemID) 
            .Commit(conn);
    }

    trans.Complete();
}

【讨论】:

  • 这实际上更像是一个评论而不是一个答案。而且我不确定我是否同意这总是最快的方法。
  • 好吧,我先把它作为评论,但既然它是正确的答案,我想我不妨把它作为答案。
  • 这当然是最好的方法之一。而且性能通常相当不错。有很多方法可以给这只猫剥皮,而你的方法很好。 :)
  • @Magnus 这是免费图书馆还是付费图书馆,你发布了参考资料?
  • Nuget 包:nuget.org/api/v2/package/SqlBulkTools/4.5.0。或输入:Install-Package SqlBulkTools -Version 4.5.0
【解决方案2】:

您可以使用Kros.KORM进行批量操作。

using (var database = new Database("connectionstring ...", "ado client name ..."))
{
    database
       .Query<Movie>()
       .AsDbSet()
       .BulkUpdate(_data);
}

或者,如果您不需要使用 ORM 并且有可用的源数据读取器,则可以使用 SqlServerBulkInsert / SqlServerBulkUpdateMsAccessBulkInsert / MsAccessBulkUpdate 类来执行批量操作。

例如:

using (var bulkInsert = new SqlServerBulkInsert("connection string"))
{
    bulkInsert.Insert(reader);
}

您可以看到与纯 ADO.NET 命令的比较https://github.com/Kros-sk/Kros.Libs/wiki

【讨论】:

  • 嘿刚刚测试了你的库!在 git 页面上设置的大多数示例都不起作用,而且它缺少批量删除...总体平均性能,尽管比标准 ADO.NET 有了很大改进!
  • 感谢您的反馈。批量删除工作正在进行中。这是我们存储库中的一个问题。我们的文档可能仍然不完美。请您指定哪些示例不起作用,最好直接在github上写问题?您将帮助我们改进我们的开源。好的,谢谢。
  • 我尝试了 SqlServerBulkUpdate,它适用于数千条记录,但它会在 100 万条记录中出现超时异常,知道吗?谢谢
【解决方案3】:

我不知道您的代码中有哪些项目,所以我不知道如何将这些项目放入表值参数中。如果您需要,我可以提供帮助,但我需要知道那个对象是什么。

不管你可以在 sql 端做这样的事情。然后,您只需使用您的项目集合作为入站参数执行此过程。

create type Items as TABLE
(
    ItemID int
    , Quantity int
)

GO

create procedure UpdateItemsBulk
(
    @Items Items READONLY
) as

    set nocount on;

    Update i
    set QuantitySold = items.Quantity
    from items i
    join @Items items on items.ItemID = i.ItemID

GO

【讨论】:

  • 嘿肖恩非常感谢您的回复:)! Items 是我的数据库中已经存在的表的映射类
  • 如果这个数据已经在数据库中,为什么还需要这样更新呢?当然,没有人会经历 50-100k 行并手动更改这些值。也许这整个挑战可以完全在数据库中解决,根本不需要 dotnet 代码?
猜你喜欢
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2011-04-05
  • 2014-02-20
  • 2015-08-03
相关资源
最近更新 更多