Как удалить большую запись из SQL Server? - PullRequest
12 голосов
/ 23 июня 2011

В базе данных форума я по ошибке установил тело на nvarchar(MAX). Ну, конечно, кто-то опубликовал Британскую энциклопедию. Так что теперь есть тема на форуме, которая не будет загружаться из-за этого сообщения. Я идентифицировал сообщение и выполнил запрос на удаление, но по какой-то причине запрос просто сидит и крутится. Я отпустил его на пару часов, и он просто сидит там. В конце концов, это истечет время ожидания.

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

Кто-нибудь еще имел эту проблему? Есть ли простой способ разбить эту злую запись на кусочки?

Обновление: Извините, версия SQL Server - 2008.

Вот запрос, который я выполняю для удаления записи:

DELETE FROM [u413].[replies] WHERE replyID=13461

Я также пытался удалить саму тему, которая имеет отношение к ответам, и удаляет по темам каскадный к связанным ответам. Это тоже зависает.

Ответы [ 3 ]

4 голосов
/ 23 июня 2011

Вариант 1. Зависит от размера самой таблицы и размера строк.

  1. Копирование данных в новую таблицу:

    SELECT *
    INTO tempTable
    FROM replies WITH (NOLOCK)
    WHERE replyID != 13461
    

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

  2. Удалить старую таблицу

    DROP TABLE replies
    

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

  3. Переименовать новую таблицу

    sp_rename 'tempTable', 'replies'
    
  4. Воссоздайте все внешние ключи, индексы и триггеры.

Опция 2. Разбиение.

  1. Добавить новый битовый столбец, называемый, скажем, «Разделение», установленный в 0 для всех строк, кроме плохой.Для плохого установите значение 1.

  2. Создайте функцию разделения, чтобы было два раздела 0 и 1.

  3. Создайте временную таблицу ста же структура, что и в исходной таблице.

  4. Переключение раздела 1 из исходной таблицы в новую временную таблицу.

  5. Удаление временной таблицы.

  6. Удалите разделение из исходной таблицы и удалите новый столбец.

Разделить тему не так просто.В Интернете есть несколько примеров, например Переключение разделов в SQL Server 2005

3 голосов
/ 23 июня 2011

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

SELECT * FROM sys.dm_os_waiting_tasks WHERE session_id = {spid}

Замените {spid} на правильный номер spid соединения, выполняющего команду DELETE. Чтобы получить это значение, запустите SELECT @@ spid перед командой DELETE.

Если столбец sys.dm_os_waiting_tasks.blocking_session_id имеет значение, вы можете использовать монитор активности, чтобы увидеть, что делает этот процесс.

Чтобы открыть монитор активности, щелкните правой кнопкой мыши имя сервера в обозревателе объектов SSMS и выберите «Монитор активности». Разделы "Процессы" и "Ожидание ресурса" - те, которые вам нужны.

1 голос
/ 23 июня 2011

Поскольку у вас возникают проблемы при удалении записи и воссоздании таблицы, вы пытались обновить запись?

Что-то вроде (изменение имени поля body в соответствии с тем, что находится в таблице):

update [u413].[replies] set body='' WHERE replyID=13461

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

alter table [u413].[replies] alter column body nvarchar(100)
...