如何强制运行t-sql查询(一半完成)提交?

时间:2014-05-08 12:25:47

标签: sql sql-server

我在Sql Server 2008 R2上有数据库。 在该数据库上,对4亿条记录的删除查询已运行4天,但我需要重启机器。我如何强制它提交到目前为止删除的内容?我想拒绝到目前为止通过运行查询删除的数据。 但问题是查询仍在运行,并且在服务器重启之前无法完成。

注意:我没有为查询设置任何隔离/开始/结束事务。该查询在SSMS studio中运行。

如果机器重启或我取消了查询,那么数据库将进入恢复模式,它将在接下来的2天内恢复,然后我需要重新运行删除,这将花费我4天。

我非常感谢任何建议/帮助或指导。 我是sql server的新手用户。

先谢谢 此致

3 个答案:

答案 0 :(得分:3)

无法阻止SQL Server尝试将数据库置于事务一致状态。每个语句都隐式地是一个事务本身(如果不是外部事务的一部分)并且正在执行全部或全部。因此,如果您取消查询或断开连接或重新启动服务器,SQL Server将从事务日志中将原始值写回更新的数据页。

下次一次删除这么多行时,请不要一次删除。将作业划分为较小的块(我总是使用5.000作为幻数,这意味着我在循环中删除了5000行)以最小化事务日志的使用和锁定。

set rowcount 5000
delete table
while @@rowcount = 5000
    delete table
set rowcount 0

答案 1 :(得分:3)

如果要删除那么多行,您可能会有更好的截断时间。截断非常有效地删除表中的所有行。但是,我假设你想保留表中的一些记录。下面的存储过程将您要保留的数据备份到临时表中,然后截断然后重新插入已保存的记录。这可以很快清理一张巨大的桌子。

请注意,truncate不能很好地使用外键约束,因此您可能需要删除它们,然后在清理后重新创建它们。

CREATE PROCEDURE [dbo].[deleteTableFast] ( 
@TableName VARCHAR(100),
@WhereClause varchar(1000)) 
AS 
BEGIN
-- input:
-- table name: is the table to use
-- where clause: is the where clause of the records to KEEP

declare @tempTableName varchar(100);
set @tempTableName = @tableName+'_temp_to_truncate';

-- error checking
if exists (SELECT [Table_Name] FROM Information_Schema.COLUMNS WHERE [TABLE_NAME] =(@tempTableName)) begin
print 'ERROR: already temp table ... exiting'
return
end
if not exists (SELECT [Table_Name] FROM Information_Schema.COLUMNS WHERE [TABLE_NAME] =(@TableName)) begin
print 'ERROR: table does not exist ... exiting'
return
end

-- save wanted records via a temp table to be able to truncate
exec ('select * into '+@tempTableName+' from '+@TableName+' WHERE '+@WhereClause);
exec ('truncate table '+@TableName);
exec ('insert into '+@TableName+' select * from '+@tempTableName);
exec ('drop table '+@tempTableName);

end
GO

答案 2 :(得分:1)

在了解数据库进入恢复模式的原因之前,您必须先了解ACID中的D(持久性)。

一般来说,如果可能的话,应该避免长时间运行SQL。长时间运行的SQL意味着更多的资源锁定时间,更大的事务日志以及失败时的巨大回滚时间。

考虑将你的任务分成一些id或时间。例如,您希望将大型数据从TableSrc插入TableTarget,您可以编写类似

的查询
DECLARE @BATCHCOUNT INT = 1000;
DECLARE @Id INT = 0;
DECLARE @Max = ...;
WHILE Id < @Max
BEGIN
    INSERT INTO TableTarget
    FROM TableSrc
    WHERE PrimaryKey >= @Id AND @PrimaryKey < @Id + @BatchCount;
    SET @Id = @Id + @BatchCount;
END

它的代码更难看,更容易出错。但这是我知道处理大量数据的唯一方法。