是否可以取消 Sql Bulk Copy.Write To Server (c#)?
Is it possible to cancel a SqlBulkCopy.WriteToServer (c#)?
我正在使用 Sql Bulk Copy.Write To Server (C#) 复制数十亿行,这需要几个小时才能完成。有时因为一些紧急的任务需要停止运行,但我不知道该怎么做。我可以在通知事件到达时做些什么吗(使用 Sql Bulk Copy.NotifyAfter 和 Sql Bulk Copy.SqlRowsCopied)?
您可以尝试修改您的 sql 查询并分块处理数据,例如,每个请求 1000 个。如果您需要停止操作,请记住块大小和数量,停止 sql 操作,执行您需要的操作,然后继续 sql 操作。
您也可以制作自己的 PaueOperationToken
,例如 CancelToken
。
这是 CancelToken
中的 example。
Can I do something on the arriving of the notification event
作为 SQL 管理员,您总是可以找到会话 运行 批量加载和 KILL 它,就像这样:
declare @spid int = (
select session_id
from sys.dm_exec_requests
where command = 'BULK INSERT')
if @spid is not null
begin
declare @sql varchar(200) = concat('kill ',@spid)
exec ( @sql )
end
如果您想在代码中执行此操作,请使用接受取消令牌的 WriteToServer 的异步版本。例如
static void Main(string[] args)
{
using (var src = new SqlConnection("server=.;database=tempdb;integrated security=true"))
using (var dest = new SqlConnection("server=.;database=tempdb;integrated security=true"))
{
src.Open();
dest.Open();
var cmd = new SqlCommand("create table #t(id int)", dest);
cmd.ExecuteNonQuery();
bool cancel = false;
var cancelationTokenSource = new CancellationTokenSource();
var srcCmd = new SqlCommand("select row_number() over (order by (select null)) id from sys.objects o, sys.columns c, sys.columns c2", src);
using (var rdr = srcCmd.ExecuteReader())
{
var bc = new SqlBulkCopy(dest);
bc.NotifyAfter = 10000;
bc.SqlRowsCopied += (s, a) =>
{
Console.WriteLine($"{a.RowsCopied} rows copied");
if (cancel)
{
dest.Close();
}
};
bc.DestinationTableName = "#t";
bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping("id", "id"));
var task = bc.WriteToServerAsync(rdr, cancelationTokenSource.Token);
Console.WriteLine("Hit any key to cancel the bulk load");
while (!task.Wait(1000))
{
if (Console.KeyAvailable)
{
cancelationTokenSource.Cancel();
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine("WriteToServer Canceled");
break;
}
}
}
Console.WriteLine("Hit any key to exit");
return;
}
}
}
If the user wants to cancel the operation from the event, the Abort
property of the SqlRowsCopiedEventArgs can be used.
所以下面的代码应该可以解决问题:
SqlBulkCopy cp = new SqlBulkCopy("your connection string");
cp.NotifyAfter = 1000; // use here whatever number floats your boat
cp.SqlRowsCopied += (sender, eventArgs) => eventArgs.Abort = true; // add some more conditions here
我正在使用 Sql Bulk Copy.Write To Server (C#) 复制数十亿行,这需要几个小时才能完成。有时因为一些紧急的任务需要停止运行,但我不知道该怎么做。我可以在通知事件到达时做些什么吗(使用 Sql Bulk Copy.NotifyAfter 和 Sql Bulk Copy.SqlRowsCopied)?
您可以尝试修改您的 sql 查询并分块处理数据,例如,每个请求 1000 个。如果您需要停止操作,请记住块大小和数量,停止 sql 操作,执行您需要的操作,然后继续 sql 操作。
您也可以制作自己的 PaueOperationToken
,例如 CancelToken
。
这是 CancelToken
中的 example。
Can I do something on the arriving of the notification event
作为 SQL 管理员,您总是可以找到会话 运行 批量加载和 KILL 它,就像这样:
declare @spid int = (
select session_id
from sys.dm_exec_requests
where command = 'BULK INSERT')
if @spid is not null
begin
declare @sql varchar(200) = concat('kill ',@spid)
exec ( @sql )
end
如果您想在代码中执行此操作,请使用接受取消令牌的 WriteToServer 的异步版本。例如
static void Main(string[] args)
{
using (var src = new SqlConnection("server=.;database=tempdb;integrated security=true"))
using (var dest = new SqlConnection("server=.;database=tempdb;integrated security=true"))
{
src.Open();
dest.Open();
var cmd = new SqlCommand("create table #t(id int)", dest);
cmd.ExecuteNonQuery();
bool cancel = false;
var cancelationTokenSource = new CancellationTokenSource();
var srcCmd = new SqlCommand("select row_number() over (order by (select null)) id from sys.objects o, sys.columns c, sys.columns c2", src);
using (var rdr = srcCmd.ExecuteReader())
{
var bc = new SqlBulkCopy(dest);
bc.NotifyAfter = 10000;
bc.SqlRowsCopied += (s, a) =>
{
Console.WriteLine($"{a.RowsCopied} rows copied");
if (cancel)
{
dest.Close();
}
};
bc.DestinationTableName = "#t";
bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping("id", "id"));
var task = bc.WriteToServerAsync(rdr, cancelationTokenSource.Token);
Console.WriteLine("Hit any key to cancel the bulk load");
while (!task.Wait(1000))
{
if (Console.KeyAvailable)
{
cancelationTokenSource.Cancel();
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine("WriteToServer Canceled");
break;
}
}
}
Console.WriteLine("Hit any key to exit");
return;
}
}
}
If the user wants to cancel the operation from the event, the Abort property of the SqlRowsCopiedEventArgs can be used.
所以下面的代码应该可以解决问题:
SqlBulkCopy cp = new SqlBulkCopy("your connection string");
cp.NotifyAfter = 1000; // use here whatever number floats your boat
cp.SqlRowsCopied += (sender, eventArgs) => eventArgs.Abort = true; // add some more conditions here