Перемещение данных SQL Server в ограниченных (1000 строк) кусках
Я пишу процесс, который архивирует строки из таблицы SQL Server на основе столбца datetime. Я хочу переместить все строки с датой до X, но проблема в том, что для каждой даты есть миллионы строк, поэтому делаем транзакцию BEGIN...ВСТАВЛЯТЬ...УДАЛИТЬ...Фиксация для каждой даты занимает слишком много времени и блокирует базу данных для других пользователей.
есть ли способ сделать это меньшими кусками? Может быть, используя ROWCOUNT или что-то в этом роде?
Я изначально считать что-то вроде этого:
SET ROWCOUNT 1000
DECLARE @RowsLeft DATETIME
DECLARE @ArchiveDate DATETIME
SET @ROWSLEFT = (SELECT TOP 1 dtcol FROM Events WHERE dtcol <= @ArchiveDate)
WHILE @ROWSLEFT IS NOT NULL
BEGIN
INSERT INTO EventsBackups
SELECT top 1000 * FROM Events
DELETE Events
SET @ROWSLEFT = (SELECT TOP 1 dtcol FROM Events WHERE dtcol <= @ArchiveDate)
END
но потом я понял, что я не могу гарантировать, что строки Я удалю это те, что я попятился. Или могу...?
обновление: Другие варианты я бы рассмотрел еще на шаг:
- выберите верхние 1000 строк, которые соответствуют моим критериям даты в временную таблицу
- Начать Транзакцию
- вставить из таблицы temp в таблицу архива
- удалить из источника таблица, присоединение к таблице temp через каждый столбец
- совершают сделки
- повторите 1-5, пока не останется строк, соответствующих критериям даты
есть ли у кого-нибудь идея о том, как расход этой серии может сравниться с некоторыми другими вариантами, обсуждаемыми ниже?
деталь: Я использую SQL 2005, так как кто-то спросил.
8 ответов
просто вставьте результат удаления:
WHILE 1=1
BEGIN
WITH EventsTop1000 AS (
SELECT TOP 1000 *
FROM Events
WHERE <yourconditionofchoice>)
DELETE EventsTop1000
OUTPUT DELETED.*
INTO EventsBackup;
IF (@@ROWCOUNT = 0)
BREAK;
END
это атомарный и последовательный.
используйте INSERT с предложением OUTPUT INTO для хранения идентификаторов вставленных строк, а затем удалите присоединение к этой временной таблице, чтобы удалить только эти идентификаторы
DECLARE @TempTable (YourKeyValue KeyDatatype not null)
INSERT INTO EventsBackups
(columns1,column2, column3)
OUTPUT INSERTED.primaryKeyValue
INTO @TempTable
SELECT
top 1000
columns1,column2, column3
FROM Events
DELETE Events
FROM Events
INNER JOIN @TempTable t ON Events.PrimaryKey=t.YourKeyValue
Как насчет:
INSERT INTO EventsBackups
SELECT TOP 1000 * FROM Events ORDER BY YourKeyField
DELETE Events
WHERE YourKeyField IN (SELECT TOP 1000 YourKeyField FROM Events ORDER BY YourKeyField)
Как насчет не делать все сразу?
INSERT INTO EventsBackups
SELECT * FROM Events WHERE date criteria
потом
DELETE FROM Events
SELECT * FROM Events INNER JOIN EventsBackup on Events.ID = EventsBackup.ID
или эквивалент.
ничто из того, что вы сказали до сих пор, не предполагает, что вам нужна транзакция.
У вас есть индекс на поле? Если у вас нет sql, может быть вынужден перейти на блокировку таблицы, которая заблокирует всех ваших пользователей во время выполнения инструкций архива.
Я думаю, вам понадобится индекс для этой операции, чтобы выполнить все хорошо! Поставить индекс на поле даты и повторите операцию!
не могли бы вы сделать копию события, переместить все строки с датами >= x к этому, отбросить события и переименовать события копирования? Или скопировать, обрезать и затем скопировать обратно? Если вы можете позволить себе немного простоя, это, вероятно, будет самый быстрый подход.
вот что я делал:
SET @CleanseFilter = @startdate
WHILE @CleanseFilter IS NOT NULL
BEGIN
BEGIN TRANSACTION
INSERT INTO ArchiveDatabase.dbo.MyTable
SELECT *
FROM dbo.MyTable
WHERE startTime BETWEEN @startdate AND @CleanseFilter
DELETE dbo.MyTable
WHERE startTime BETWEEN @startdate AND @CleanseFilter
COMMIT TRANSACTION
SET @CleanseFilter = (SELECT MAX(starttime)
FROM (SELECT TOP 1000
starttime
FROM dbo.MyTable
WHERE startTime BETWEEN @startdate AND @enddate
ORDER BY starttime) a)
END
Я не вытягиваю ровно 1000, просто 1000ish, поэтому он обрабатывает повторения в столбце времени соответствующим образом (что-то, о чем я беспокоился, когда я рассматривал использование ROWCOUNT). Поскольку в столбце time часто повторяются повторы, я вижу, что он регулярно перемещает 1002 или 1004 строки/итерации, поэтому я знаю, что он получает все.
Я представляю это как ответ, чтобы его можно было судить по другим решениям, которые люди предоставили. Позволить мне знайте, есть ли что-то явно неправильное в этом методе. Спасибо всем за помощь, и я приму тот ответ, за который проголосует больше всех через несколько дней.
другой вариант-добавить процедуру запуска в таблицу событий, которая ничего не делает, кроме добавления той же записи в таблицу EventsBackup.
таким образом, EventsBackup всегда обновлен, и все, что вы делаете, это периодически очищать записи из таблицы событий.