SQL Server 2000 Удалить Top (1000)

У меня есть большая база данных SQL Server с таблицей около 45 миллионов записей. Я архивирую эту таблицу и мне нужно удалить все записи больше двух лет назад. У меня вставка в мою таблицу архивов работает нормально, но у меня проблемы с эффективностью при удалении.

Моя проблема заключается в индексах, находящихся в настоящее время в таблице. Я хотел бы удалить (и архивную вставку) в 1000 блоков записей. Для этого мне нужно определить "лучшие" 1000 записей, удовлетворяющих требованию (больше двух лет). Штамп DateTime в строке является кластеризованным индексом, поэтому это отлично подходит для захвата строк. Однако SQL 2000 не позволяет DELETE TOP 1000.... так что мне нужно сделать что-то вроде:

DELETE FROM <table> WHERE [UniqueID] IN 
(SELECT TOP 1000 [UniqueID] FROM <table> WHERE [DateTime] < @TwoYearsAgo)

Это отлично работает, если UniqueID был проиндексирован. Так как это не так, это занимает очень много времени (это сканирование таблицы для каждой из 1000 записей, которые нужно удалить). В таблице нет других индексов, которые однозначно идентифицируют записи. Мне сказали, что было бы слишком дорого вычислить индекс на UniqueID, так как это живая БД. Может ли кто-нибудь указать способ оптимизации этого запроса?

Ответы

Ответ 1

Как переписывать запрос?

SET ROWCOUNT 1000
DELETE FROM <table> WHERE [DateTime] < @TwoYearsAgo

См. документацию по SET ROWCOUNT (Transact-SQL).

Также обратите внимание, что в документации для DELETE она поддерживает предложение TOP, но это, по-видимому, новое для SQL Server 2005 и выше, Я говорю это, так как кажется, что он не поддерживается на вашем сервере базы данных, но вы на самом деле пытались его использовать? У меня нет доступа к документации SQL Server 2000, поэтому я не уверен, поддерживается ли она в этой версии. Это очень хорошо, возможно, не так.

DELETE TOP (1000) FROM <table> WHERE [DateTime] < @TwoYearsAgo

Обратите внимание, что отличие от способа TOP на select может быть записано без скобок. Для UPDATE, DELETE и INSERT выражение должно быть заключено в скобки, даже если это только постоянное число, как указано выше.

Ответ 2

Вы можете удалить подзапрос:

DELETE <table> FROM (
  SELECT TOP 1000 *  
  FROM <table>
  WHERE [DateTime] < @TwoYearsAgo);

См. пример E: at SQL 2000 DELETE Синтаксис. Это рекомендуется по методу SET ROWCOUNT. В SQL 2005 и более поздних версиях вы можете напрямую указать TOP в DELETE.

Ответ 3

вы также можете сделать

DELETE TOP(1000) FROM <table> WHERE [DateTime] < @TwoYearsAgo

Бог знает, почему они используют top (x) для удаления и вершины x для выбора, большинство людей даже не знают об этой функции!

edit: По-видимому, его 2005+, поэтому вы, вероятно, должны игнорировать это.

Ответ 4

Вы можете использовать SET ROWCOUNT:

SET ROWCOUNT 1000
DELETE FROM <table> WHERE [DateTime] < @TwoYearsAgo

Ответ 5

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

  • Сделайте небольшую таблицу #temp со значениями идентификаторов для верхних (x) строк. Если идентификатор действительно не может быть проиндексирован в вашем сценарии, вместо этого вы можете использовать дату и идентификатор, поэтому комбинация из них может использовать индекс.

  • begin tran

  • Вставить в архивную таблицу, где ID и DATE в (#temp)

  • Удалить из основной таблицы, где ID и DATE в (#temp)

  • фиксации

  • Обрезать #temp

  • Повторить

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

Также я согласен с Lasse - не вижу точки уникального идентификатора без индекса и, следовательно, никакого ограничения, чтобы обеспечить его соблюдение.

Ответ 6

Интересно, следует ли придерживаться требования к записи 1000 записей. Если это связано с загрузкой сервера и произвольным, вы можете попробовать следующее, так как у вас уже есть кластеризованный индекс в [DateTime]:

DELETE FROM <table> 
WHERE [DateTime] < @TwoYearsAgo 
and [DateTime] < (select dateadd(day, 1, min([DateTime])) from <table>)

Ответ 7

Для обратной совместимости скобки являются необязательными в операторах SELECT. Мы рекомендуем всегда использовать круглые скобки для операторов TOP в SELECT для согласованности с его требуемым использованием в операторах INSERT, UPDATE, MERGE и DELETE, в которых требуются скобки.

USE AdventureWorks;
GO
DELETE TOP (20) 
FROM Purchasing.PurchaseOrderDetail
WHERE DueDate < '20120701';
GO