SQLBulkCopy的任何方式“插入或更新,如果存在”?

时间:2011-02-03 16:58:28

标签: c# .net sql sql-server performance

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

如果没有,最有效的方法是什么?我再次谈论一张包含数百万条记录的表格。

谢谢

6 个答案:

答案 0 :(得分:11)

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

  • 批量加载到临时表
  • 应用MERGE语句更新/插入真实表格

详细了解MERGE statement

答案 1 :(得分:9)

我会将数据批量加载到临时临时表中,然后在最终表中进行插入。有关执行upsert的示例,请参阅http://www.databasejournal.com/features/mssql/article.php/3739131/UPSERT-Functionality-in-SQL-Server-2008.htm

答案 2 :(得分:6)

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

这是一个可以实现批量upsert的代码示例。

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

答案 3 :(得分:5)

而不是创建一个新的临时表,BTW消耗更多的空间和内存。

我使用INSTEAD OF INSERT创建了一个Trigger,并在MERGE语句中使用。

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

这是我的两分钱。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

从@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