【发布时间】:2011-06-20 19:42:15
【问题描述】:
我需要定期更新一个非常大的表,而 SQLBulkCopy 非常适合,只是我有一个 2 列索引可以防止重复。有没有办法将 SQLBulkCopy 用作“如果存在则插入或更新”?
如果不是,那么最有效的方法是什么?同样,我说的是一个包含数百万条记录的表。
谢谢
【问题讨论】:
标签: c# sql sql-server performance sqlbulkcopy
我需要定期更新一个非常大的表,而 SQLBulkCopy 非常适合,只是我有一个 2 列索引可以防止重复。有没有办法将 SQLBulkCopy 用作“如果存在则插入或更新”?
如果不是,那么最有效的方法是什么?同样,我说的是一个包含数百万条记录的表。
谢谢
【问题讨论】:
标签: c# sql sql-server performance sqlbulkcopy
我会将数据批量加载到临时临时表中,然后对最终表执行更新插入。有关执行 upsert 的示例,请参阅 here。
【讨论】:
【讨论】:
另一种选择是不使用临时表,而是使用带有表值参数的存储过程。将数据表传递给 sp 并在那里进行合并。
【讨论】:
而不是创建一个新的临时表,顺便说一句,这会消耗更多的空间和内存。
我使用 INSTEAD OF INSERT 创建了一个触发器并在 MERGE 语句中使用。
但不要忘记在 SqlBulkCopy 中添加参数 SqlBulkCopyOptions.FireTriggers。
这是我的两分钱。
【讨论】:
我发布了一个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。
【讨论】:
从@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
【讨论】: