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