Удаление большого количества строк из SQL Server - эффективно и без блокировки - PullRequest
7 голосов
/ 06 мая 2011

Я пишу процедуру для удаления всех строк из нескольких таблиц в течение n дней.

Простой простой запрос, который легко написать

DELETE FROM [myTable] 
WHERE [Created] < GETDATE()-30

Одна проблема - нетиндекс в поле даты - я мог бы добавить один, но я работал над этим, делая что-то вроде:

SELECT @var = MAX([ID]) FROM myTable WHERE Created < GETDATE()-30; 
DELETE FROM myTable WHERE ID < @var

Это кажется приемлемым методом?

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

Запуск его на (немного медленном) тестовом сервере занимает около часа, и убивает таблицу из других процессов, пытаясьдля чтения / записи в него.

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

Мои знания БД довольно просты, так как я программист, а не dba.

Может кто-нибудь дать мне достойный методдля выполнения этой задачи - максимально эффективнопуть возможен.

Ответы [ 5 ]

6 голосов
/ 06 мая 2011

Что вам нужно, так это скользящее окно на основе секций: Как реализовать автоматическое скользящее окно в многораздельной таблице на SQL Server 2005 . Разбейте таблицу по дням, и вы сможете эффективно отбросить целый день за одну операцию переключения разделов в полночь. Переключатель раздела в основном мгновенный.

Если вам нужно решение с немного меньшими накладными расходами (разбиение имеет серьезные последствия и вызывает колебания во всем приложении, особенно когда необходимо выровнять индексы, что является обязательным условием для операций быстрого переключения), то вам необходимо разработать схему в соответствии с этой операцией. С уверенностью 99,99% я могу сказать, что крайний левый кластеризованный ключ вашего myTable должен быть полем Created. Это позволит эффективно удалять партии (delete top (2500) from myTable where Created < ...). Есть много причин, по которым вы хотите, чтобы это было пакетным (топ 2500 или около того за раз), наиболее важным из которых является то, что вы должны избегать эскалации блокировок и держать размер любой отдельной транзакции в разумных пределах.

3 голосов
/ 06 мая 2011

Чтобы повысить производительность, вам следует взглянуть на создание индекса в поле «Создано», если вы часто это делаете.

Тогда вы можете использовать

DELETE FROM myTable 
WHERE Created < GETDATE()-30

Я видел, как многочасовые процессы сократились до нескольких секунд с добавлением надлежащего индекса и статистики.

Индексы легко создавать, и могут быть доступны инструменты для указания индекса и обеспечения синтаксиса. Пример: помощник по настройке SQL в MS SQL 2005 Management Studio.

3 голосов
/ 06 мая 2011

Ваш метод будет страдать от той же болезни, что и обычное удаление - у вас нет индекса на [Создано]. Поэтому ваш метод просто более запутанный.

Я бы посоветовал вам создать указанный индекс и попробовать обычное удаление на вашем тестовом сервере.

Еще одно предложение - запустите это в нерабочее время через планировщик.

2 голосов
/ 06 мая 2011

Я предполагаю, что вы не можете индексировать столбец Created (поскольку это логическое место для начала в противном случае).Исходя из этого предположения, у вас будут проблемы с производительностью и блокировками.Однако, поскольку вы используете SQL 2005, вы можете воспользоваться некоторыми новыми функциями, указанными в этой статье: http://nayyeri.net/reduce-locks-for-delete-and-update-commands-in-sql-server-2005-with-top-clause

По сути, создайте запрос, который выбирает все записи, на которые вы хотите повлиять.Запишите идентификаторы строк (которые проиндексированы) во временную таблицу.Свяжите временную таблицу с вашей таблицей, из которой вы хотите удалить, основываясь на идентификаторе.Затем используйте пакетное удаление, указанное здесь, для одновременного удаления групп.

Таким образом, вы создаете временную таблицу на основе ваших критериев даты (она не будет эффективной из-за неиндексации, но вы можетевключите NOLOCK, чтобы он не заблокировал вас).Затем вы удаляете таблицу партиями, чтобы уменьшить блокировку при фактическом удалении.

0 голосов
/ 06 мая 2011

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

create view v1 as (select * FROM myTable WHERE Created < GETDATE()-30;)
delete from v1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...