我需要定期更新一个非常大的表,而SQLBulkCopy是完美的,只有我有一个2列索引可以防止重复。有没有办法使用SQLBulkCopy作为“插入或更新,如果存在”?
如果没有,最有效的方法是什么?我再次谈论一张包含数百万条记录的表格。
谢谢
答案 0 :(得分:11)
答案 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