Могу ли я удалить записи из таблицы сервера sql в середине цикла while reader.read - PullRequest
0 голосов
/ 22 февраля 2012

Я пытаюсь использовать средство чтения данных 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 ]

4 голосов
/ 22 февраля 2012

Вы должны избегать передачи строк вплоть до клиента, просто чтобы заново загрузить их обратно на сервер.Вместо этого сделайте что-то подобное (в рамках одной транзакции):

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 голос
/ 22 февраля 2012

Вы должны потратить некоторое время, читая о транзакционной изоляции , особенно повторяемых операциях чтения.

В SQL Server оператор выбора (который поддерживает ваш читатель) выполняется (по умолчанию) в изоляции READ COMMITTED, что означает, что ваша команда удаления сможет удалять строки после их чтения, но набор строки, которые читатель читает , не могут быть изменены оператором delete во время выполнения оператора select.

Для чего стоит перенести данные из одной таблицы в другую, обычно это делается в SQL, а не в .NET.

1 голос
/ 22 февраля 2012

Есть несколько способов, во-первых, вы должны понять, что такое изоляция транзакции в SQL-сервере и когда вам нужно это использовать.

В вашем случае кажется, что вы перемещаете исторические данные в другую таблицу, поэтому использование хранимой процедуры SQL в рамках транзакции (с откатом транс) будет стоить.

1 голос
/ 22 февраля 2012

Вы должны сделать это в рамках транзакции. Это также очень хороший кандидат на 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, пока не будет ничего для резервного копирования. Поскольку это происходит внутри транзакции, вставка и удаление будут либо успешными, либо неудачными.

Независимо от того, сколько вы хотите удалить в одном, если вас беспокоит постоянство, вы должны сделать это в транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...