我正在尝试使用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
有没有理由在读者阅读时不修改基础表格?例如,如果我开始在循环中间删除记录,读者是否会使用某些索引来获取可能会改变的记录?
答案 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)将是值得的。