我可以在一段时间的reader.read循环中删除sql server表中的记录

时间:2012-02-22 18:23:17

标签: .net sql-server ado.net sqldatareader

我正在尝试使用SQL数据读取器将记录从一个表移动到一个存档表中。我想逐个记录传输(而不是集中插入和删除),以便在发生错误时,丢失最少量的数据(并且必须从备份中恢复)。

我的问题是,如果我在读取记录后删除记录,SQL阅读器是否有效?这是迄今为止我做的事情最简单直接的方式。它会打开意外错误吗?

While myReader.Read // select * from tableA where older than 1 year record
    insert the record into tableA_archive
    delete the record from tableA   
loop

这似乎模糊地类似于循环在循环中修改的列表 - 我知道在.net

中引起各种令人头疼的问题
for aItem in listA
   if aItem fits criteria, send to list B and delete from listA
next

有没有理由在读者阅读时不修改基础表格?例如,如果我开始在循环中间删除记录,读者是否会使用某些索引来获取可能会改变的记录?

4 个答案:

答案 0 :(得分:4)

您应该避免将行一直传输到客户端,只是将它们重新上传回服务器。相反,做这样的事情(在同一个交易中):

INSERT INTO NEW_TABLE SELECT * FROM OLD_TABLE WHERE condititon;
DELETE FROM OLD_TABLE WHERE condititon;

甚至是MS SQL Server特定的:

DELETE FROM OLD_TABLE OUTPUT DELETED.* INTO NEW_TABLE WHERE condition;

(所有条件都相同)

如果您愿意,您甚至可以从.NET代码执行这些语句,并且仍然保留下载所有行的好处。

答案 1 :(得分:1)

您应该在交易中执行此操作。这也是SP的一个非常好的候选者,即使你也可以在代码中做到这一点。您必须找出导致相当数量的行的条件(不是1但可能是100或1000或10000)。尝试并找出在合理的时间内(可能是几秒钟)在一个语句中插入和删除的数量。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

BEGIN TRAN
    INSERT INTO tableA_archive (col1, col2)
        SELECT col1, col2 FROM tableA WHERE (SomeCondition)
    DELETE FROM tableA  WHERE (SomeCondition)
COMMIT TRAN

SomeCondition可以是日期范围(例如一天,一小时等)。

然后在循环中运行此过程,更改SomeCondition直到没有任何要备份的内容。由于这是在一个事务中,插入和删除都会成功或失败。

无论您想在一个中删除多少,如果您担心一致性,您必须在一个事务中执行此操作。

答案 2 :(得分:1)

您应该花一些时间阅读transactional isolation,特别是可重复读取。

在SQL Server中,select语句(支持读者)在READ COMMITTED隔离中执行(默认情况下),这意味着删除命令可以在读取后删除行,但集合

执行select语句时,delete语句无法修改读取器读取的行

对于它的价值,将数据从一个表移动到另一个表通常应该在SQL中完成,而不是在.NET中完成。

答案 3 :(得分:1)

有几种方法,首先你必须了解什么是事务隔离 在SQL Server中,何时需要使用它。

在您的情况下,您似乎正在将历史数据移动到另一个表,因此在事务范围内使用SQL存储过程(使用rollback trans)将是值得的。