【问题标题】:Any way to SQLBulkCopy "insert or update if exists"?SQLBulkCopy“如果存在则插入或更新”的任何方式?
【发布时间】:2011-06-20 19:42:15
【问题描述】:

我需要定期更新一个非常大的表,而 SQLBulkCopy 非常适合,只是我有一个 2 列索引可以防止重复。有没有办法将 SQLBulkCopy 用作“如果存在则插入或更新”?

如果不是,那么最有效的方法是什么?同样,我说的是一个包含数百万条记录的表。

谢谢

【问题讨论】:

    标签: c# sql sql-server performance sqlbulkcopy


    【解决方案1】:

    我会将数据批量加载到临时临时表中,然后对最终表执行更新插入。有关执行 upsert 的示例,请参阅 here

    【讨论】:

    • 我对 SSIS 不太熟悉,它究竟对完成这项任务有什么帮助?
    • 这是一项非常昂贵的业务。创建一个临时表,然后合并。
    【解决方案2】:

    不是一步到位,而是在 SQL Server 2008 中,您可以:

    • 批量加载到暂存表中
    • 应用MERGE 语句来更新/插入您的真实表

    阅读更多关于MERGE statement

    【讨论】:

      【解决方案3】:

      另一种选择是不使用临时表,而是使用带有表值参数的存储过程。将数据表传递给 sp 并在那里进行合并。

      【讨论】:

        【解决方案4】:

        而不是创建一个新的临时表,顺便说一句,这会消耗更多的空间和内存。

        我使用 INSTEAD OF INSERT 创建了一个触发器并在 MERGE 语句中使用。

        但不要忘记在 SqlBulkCopy 中添加参数 SqlBulkCopyOptions.FireTriggers。

        这是我的两分钱。

        【讨论】:

          【解决方案5】:

          我发布了一个nuget包(SqlBulkTools)来解决这个问题。

          这是一个实现批量更新插入的代码示例。

          var bulk = new BulkOperations();
          var books = GetBooks();
          
          using (TransactionScope trans = new TransactionScope())
          {
              using (SqlConnection conn = new SqlConnection(ConfigurationManager
              .ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
              {
                  bulk.Setup<Book>()
                      .ForCollection(books)
                      .WithTable("Books")
                      .AddAllColumns()
                      .BulkInsertOrUpdate()
                      .MatchTargetOn(x => x.ISBN)
                      .Commit(conn);
              }
          
              trans.Complete();
          }
          

          对于非常大的表,可以选择添加表锁和临时禁用非聚集索引。有关更多示例,请参阅SqlBulkTools Documentation

          【讨论】:

          • 我不得不说,这个图书馆充满了美好。我必须编写一个 Windows 服务来完成一些 ETL 工作,并且数据库交互不足以证明 MicroORM 的合理性,而这个库 SqlBulkTools 是完美的。谢谢!。干得好!
          • 文档链接已失效 (404)。
          • SqlBulkTools 已出售给 ZZZ Projects。
          • 现在是 2020 年,我正在使用这个包。性能很棒,这正是我批量插入或更新所需要的!
          • 也很好用,有什么想法可以使用 CancellationToken 来解决部分操作(因为这些操作可能会运行很长时间)?
          【解决方案6】:

          从@Ivan 那里得到了提示。对于那些可能需要的人,这就是我所做的。

          create trigger yourschma.Tr_your_triger_name
              on yourschma.yourtable
              instead of INSERT
              as
              merge into yourschma.yourtable as target
              using inserted as source
              on (target.yourtableID = source.yourtableID)
              when matched then
                  update
                  set target.ID     = source.ID,
                      target.some_column = source.some_column,
                      target.Amount                       = source.Amount
              when not matched by target then
                  insert (some_column, Amount)
                  values (source.some_column, source.Amount);
          go
          

          【讨论】:

            猜你喜欢
            • 2020-07-05
            • 1970-01-01
            • 2021-02-04
            • 2019-01-16
            • 1970-01-01
            • 2018-01-31
            • 1970-01-01
            • 1970-01-01
            • 2015-03-31
            相关资源
            最近更新 更多