2013-03-21 4 views
9

У меня есть очень большой стол, поэтому я использую следующий для удаления старых записей:SQL Server удалить с помощью цикла WHILE не работает

WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
END 

Я запускаю это несколько раз, используя разные даты. Иногда он работает нормально (занимает около 20 минут), но в других случаях запрос заканчивается немедленно, и ничего не удаляется. Когда это произойдет, я просто сделаю простой оператор SELECT из этой таблицы, а затем снова попытаюсь выполнить вышеуказанный оператор WHILE, а затем он будет работать! Кто-нибудь знает, почему это? Мне нужно автоматизировать этот запрос для регулярной работы, чтобы контролировать размер таблицы, но я хочу убедиться, что он действительно удалит правильно, когда он запускается. Спасибо.

+6

Не следует дата записывается как ' '2013-01-03'', а не как число? –

+0

Смешно, что каждый ответ полностью пропустил это. –

+4

Также обратите внимание, что просто наличие цикла не обязательно уменьшает влияние на журнал или параллелизм в зависимости от того, является ли это одной транзакцией.Я бы прекратил использовать @@ ROWCOUNT для управления, добавлял транзакции внутри цикла и задавал переменную = @@ ROWCOUNT. См. Http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes –

ответ

8

Предположительно, причина в том, что @@ROWCOUNT инициализируется значением 0.

Вы можете запустить этот запрос первым, чтобы установить его:

select count(*) from myTable where date < 20130103 

Это бы добавить немного времени, чтобы ваш запрос, но вы увидите количество удаляемых строк.

Вы также могли бы сделать что-то вроде:

select top 1  * from myTable 

, который будет идти гораздо быстрее.

+8

Вы также можете просто «ВЫБРАТЬ 1;» перед циклом. –

27

Что вы используете перед этим блоком кода? @@ROWCOUNT будет настроен на то, что он сделал. Если вы запустите некоторую другую команду заранее, это может быть 0.

Вместо этого, вы можете заставить начальный счет быть 1:

DECLARE @Rows INT 
SET @Rows = 1 

WHILE (@Rows > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 

    SET @Rows = @@ROWCOUNT 
END 
4

Это потому, что иногда @@ROWCOUNT равна нулю, чтобы начать с - поэтому цикл while никогда не выполняется, так как он проверяет состояние перед тем каждое исполнение , в том числе первый.

Вот домашнее do-while цикл, так как SQL Server не имеет один встроенный

loop: 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
if @@ROWCOUNT > 0 goto loop 
+1

У SQL Server нет ['WHILE'loop] (http://msdn.microsoft.com/en-us/library/ms178642 (v = sql.100) .aspx)? –

+5

@AaronBertrand он говорит о цикле 'do-while'. Как в: 'DO BEGIN END WHILE ' (всегда проверяет состояние «»). ЭТО НЕ существует в SQL Server. – EvilBob22

1

Вы также можете написать свой запрос так:.

SET ROWCOUNT 5000; -- set batch size 
WHILE EXISTS (SELECT 1 FROM myTable WHERE date < '2013-01-03') 
BEGIN 
    DELETE FROM myTable 
    WHERE date < '2013-01-03' 
END; 
SET ROWCOUNT 0; -- set batch size back to "no limit" 

В любом случае, вы должны форматировать ваши строки даты правильно.

Просто убедитесь, что ваши критерии удаления и инструкция в вашем предложении существуют одинаково или вы можете встретить бесконечный цикл.

+3

Помните, что после SQL 2012: «Использование SET ROWCOUNT не повлияет на операторы DELETE, INSERT и UPDATE в будущей версии SQL Server. Избегайте использования инструкций SET ROWCOUNT с DELETE, INSERT и UPDATE в новых разработках и планируйте изменить приложения, которые в настоящее время используют его. Для аналогичного поведения используйте синтаксис TOP. " –

0

В основном,

SELECT 0 -- rowcount is 1 
WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
END 

Или

SET ROWCOUNT 5000 -- set row count to 5000 
SELECT 0 -- rowcount is 1 
WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE FROM myTable 
    WHERE date < 20130103 
END 
SET ROWCOUNT 0 -- set rowcount to unlimited 
Смежные вопросы