2009-12-17 3 views
14

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

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

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

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

+3

Как вам удалось добавить столбец с именем UniqueID, который идентифицирует строки, но не имеет индекса? У вас нет первичного ключа? –

+0

Я не проектировал стол, я новый программист проекта, порученного его архивированию. Это тяжелая таблица записи (используется для ведения журнала), но не так много в плане чтения, поэтому создание дополнительного индекса (или ПК, если на то пошло) приведет к ненужным добавлениям времени вставки. Опять же, это не то, как я бы это разработал, но это то, что есть. – Kevin

+3

Человек, который сказал вам, что слишком дорого индексировать, врет. :-) – onupdatecascade

ответ

17

Как насчет переписывания запроса?

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 

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

+0

Я также пытаюсь перейти на Server 2008, но мы, скорее всего, собираемся обрезать базу данных, прежде чем переместить ее в новый экземпляр. – Kevin

+0

Да, я пробовал как с круглыми скобками, так и без них, безрезультатно. – Kevin

+0

Обратите внимание, что в соответствии с документами MSDN 'SET ROWCOUNT' больше не будет влиять на вставку, удаление и обновление операторов в следующей версии после SQL Server 2012. Так что если вы хотите, чтобы запрос, который работает на всех версиях, вам нужно было бы сделать' delete from (select top ...) ' – ChrisWue

2

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

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

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

3

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

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

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

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

1

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

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

  2. начинает Tran

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

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

  5. совершить

  6. Truncate #temp

  7. Повтор в

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

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

+0

Я пробовал что-то похожее на это с локально объявленной временной таблицей, но без индексации уникального идентификатора это мало помогло. Я попробую использовать как дату, так и уникальный идентификатор, посмотрим, доставит ли она меня где угодно. Благодаря! – Kevin

8

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

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

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

0

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

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

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

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