Как удалить все, кроме последних 20 000 записей в MS SQL 2005?

Каждую ночь мне нужно обрезать таблицу, чтобы она содержала только последние 20 000 записей. Я мог бы использовать подзапрос:

delete from table WHERE id NOT IN (select TOP 20000 ID from table ORDER BY date_added DESC)

Но это кажется неэффективным, особенно если позже мы решим сохранить 50 000 записей. Я использую SQL 2005 и подумал, что могу как-то использовать ROW_NUMBER() OVER для этого? Упорядочить их и удалить все, у которых ROW_NUMBER больше 20 000? Но я не мог заставить его работать. Является ли подзапрос моим лучшим выбором или есть лучший способ?


person Ryan Stille    schedule 12.11.2008    source источник


Ответы (6)


Если это просто кажется неэффективным, я бы убедился, что это неэффективно, прежде чем начать лаять не на то дерево.

Измерьте время, использование процессора, дисковый ввод-вывод и т. д., чтобы увидеть, насколько хорошо он работает. Я думаю, вы обнаружите, что он работает лучше, чем вы думаете.

person Lasse V. Karlsen    schedule 12.11.2008
comment
Вы правы, для очистки таблицы, содержащей около 50 000 записей, требуется всего 3 секунды. Я думал, что предложения IN() очень неэффективны, но, возможно, это происходит только тогда, когда вы фактически передаете текстовый список идентификаторов. Спасибо за помощь. - person Ryan Stille; 13.11.2008
comment
Да, предложение IN() с 20 000 идентификаторов, разделенных запятыми, вероятно, было бы довольно неэффективным. Могу поспорить, что он все равно будет выполняться примерно за 10-15 секунд. - person MusiGenesis; 13.11.2008
comment
Конечно, если он согласится разобрать даже такую ​​длинную строку. - person MusiGenesis; 13.11.2008
comment
Ознакомьтесь с моим альтернативным решением (stackoverflow.com/questions/285614/), что позволяет избежать вложенных запросов. Я протестировал 3 решения с 60к строк данных и оно оказалось самым быстрым по плану выполнения. - person Haoest; 13.11.2008

Конечно, ваш пробег будет варьироваться — это будет зависеть от того, сколько реальных записей вы очищаете от нижней части этой таблицы, но вот альтернатива.

Боковое примечание. Поскольку у вас есть поле «Date_Added», стоит ли просто сохранить дату и время последнего запуска и использовать его в предложении where для фильтрации удаляемых записей? Теперь вместо 20 000 записей разрешить Х дней в журнале... Просто мысль...


-- Поместите записи, которые мы хотим СОХРАНИТЬ, во временную папку.
-- Вы можете классифицировать хранителей по своему усмотрению.

select top 20000 * into #myTempTable from MyTable ORDER BY DateAdded DESC

-- Использование truncate не уничтожает наш файл журнала и использует меньше системных ресурсов...

truncate table MyTable 

-- Верните наши "сохраненные" записи обратно в папку...
-- Это предполагает, что вы НЕ используете столбец идентификаторов -- если да, то должны
-- указать вместо этого имена полей использовать '*' и сделать что-то вроде
-- SET IDENTITY_INSERT MyTable ON
-- вставить в MyTable select field1,field2,field3 из #myTempTable
-- (я думаю, это правильно)

insert into MyTable select * from #myTempTable

- быть хорошим гражданином.

drop table #myTempTable


Надеюсь, поможет --

person Borzio    schedule 12.11.2008

DECLARE @limit INT
SELECT @limit = min(id) FROM
   (SELECT TOP 20000 id FROM your_table ORDER BY id DESC)x
DELETE FROM your_table where id < @limit

Дело было в том, чтобы избежать вложенного запроса, который я могу или не могу оптимизировать (извините, не гуру sql.)

person Haoest    schedule 13.11.2008
comment
И этот подход, и подход с временной таблицей — отличные идеи, о которых я бы никогда не подумал. Я люблю этот сайт. - person Ryan Stille; 13.11.2008

вставьте 20000 во временную таблицу, затем удалите все записи из основной таблицы, затем снова вставьте запись 20000 из временной таблицы в основную таблицу..,

person Santosh Dube    schedule 16.12.2012

Конечно, это лучший случай для включения в процедуру и использования двух операторов sql: первый для выбора последнего идентификатора и вычитания 20 000, а затем второй для удаления всех строк с идентификатором ниже этого.

Однако на первый взгляд это звучит так, как будто при таком подходе вы получите большую фрагментацию, и это может быть хорошим аргументом в пользу создания новой таблицы, вставки в нее последних 20 000 записей, удаления старой. один и переименование нового. Возможно, даже стоит поместить таблицу в другую базу данных и создать представление из вашей основной базы данных для облегчения доступа. Лично я обычно делаю это с таблицами, используемыми для загрузки и аудита данных.

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

person Cruachan    schedule 12.11.2008
comment
Я думал сделать это так, как вы описываете в первом абзаце, но это предполагает, что в идентификаторах записей нет пробелов. Я думаю, что так и будет, и это может сработать. - person Ryan Stille; 13.11.2008

Ваш вопрос подразумевает, что вы обрезаете, чтобы получить лучшую дневную производительность за столом. Вы получаете сканирование таблиц по дневным запросам? Разве лучшие индексы не были бы ответом? Или вы находитесь в ситуации, когда вы застряли с «дерьмовой схемой»?

Или у вас есть действительно странная ситуация, когда вам действительно нужно очистить старые записи? 20 000 — это твердое и быстрое число? Или может ли дата-время работать? Затем и индекс в столбце даты и времени облегчит обрезку.

person John Dyer    schedule 13.11.2008
comment
Изначально я планировал использовать дату, например, удалить все записи старше 2 недель. Но клиент специально хотел оставить точное число вместо этого. Его аргументация заключалась в том, что мы не можем случайно исчерпать пространство, если что-то выйдет из строя в течение нескольких дней. - person Ryan Stille; 13.11.2008