Как вывести запрос SQL Server 2008 из состояния KILLED / ROLLBACK? - PullRequest
5 голосов
/ 12 мая 2010

У меня есть хранимая процедура, которая вставляет в базу данных SQL пакеты из миллионов строк, возникающих из определенного запроса. У него есть один параметр, выбирающий партию; если этот параметр пропущен, он соберет список пакетов и рекурсивно вызовет себя, чтобы выполнить итерацию по пакетам. В (псевдо) коде это выглядит примерно так:

CREATE PROCEDURE spProcedure AS BEGIN
    IF @code = 0  BEGIN
        ...
        WHILE @@Fetch_Status=0 BEGIN
            EXEC spProcedure @code
            FETCH NEXT ... INTO @code
        END
    END
    ELSE BEGIN

        -- Disable indexes
        ...

        INSERT INTO table
        SELECT (...)

        -- Enable indexes
        ...

Теперь может случиться, что эта процедура медленная по любой причине: она не может получить блокировку, один из используемых индексов неверно определен или отключен. В этом случае я хочу иметь возможность завершить процедуру, обрезать и воссоздать полученную таблицу и повторить попытку. Однако, когда я пытаюсь завершить процедуру, процесс часто переходит в состояние KILLED / ROLLBACK, откуда, похоже, нет возврата. Из Google я научился делать sp_lock, найти спид и затем убить его с помощью KILL <spid>. Но когда я пытаюсь убить его, он говорит мне

SPID 75: откат транзакции в прогресс. Расчетный откат Завершение: 0%. Расчетное время Осталось: 554 секунды.

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

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

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

Ответы [ 6 ]

10 голосов
/ 12 мая 2010

Несколько комментариев.

Во-первых, gbn верен в том, что не может отменить выполняемый откат. Таким образом, SQL сохраняет целостность транзакций, и вы не захотите хотеть , чтобы это поведение изменилось. Если вам абсолютно все равно, и вы просто хотите вернуть свою БД туда, где вы находились, когда была сделана последняя резервная копия, выполните его действия.

Одна оговорка, однако. Временами я видел, что спид на самом деле не откатывается , он просто завис (обычно с 0% или 100% прогрессом). Наиболее надежным индикатором в этом случае является то, что счетчики CPU / IO для spid в мониторе активности не изменяются (и SPID не блокируется другим SPID). В этом случае вам может потребоваться перезапустить службу SQL (не нужно выполнять полную перезагрузку), чтобы очистить spid.

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

    WHILE @@Fetch_Status=0 BEGIN
        BEGIN TRANS
            EXEC spProcedure @code
        COMMIT TRANS
        FETCH NEXT ... INTO @code
    END

Данные фиксируются после каждой партии. Если у вас возникла проблема, и вам нужно убить спид, он должен откатить только текущий пакет, над которым он работает.

Если даже одного пакета слишком много, вы, вероятно, могли бы реорганизовать свой spProcedure, чтобы вставить в меньшие партии записей по 10–100 тыс., Фиксируя после каждой.

9 голосов
/ 12 мая 2010

Откат транзакции.

Это будет продолжаться, даже если вы перезапустите экземпляр.

Если вы вставили или удалили 100 миллионов строк из 99 миллионов строк, нужно откатить все 99 миллионов строк. Вы не можете изменить это поведение. Любой отдельный оператор DML является атомарным.

Если вы хотите это исправить:

  • Стоп SQL Server
  • Удалить файлы БД
  • Запустить SQL Server
  • УДАЛИТЬ БД в неисправном состоянии
  • Восстановление

YMMV конечно: -)

2 голосов
/ 12 мая 2010

Был здесь.В прошлый раз для нас обрабатывалось где-то около 3,2 миллиарда записей.Первоначальное утверждение составило 99% за десять минут;затем провел 20 часов на IO.

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

1 голос
/ 12 мая 2010

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

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

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

1 голос
/ 12 мая 2010

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

Если что-то вроде nolock не поможет вам преодолеть существующую блокировку (вы не упомянули, является ли она эксклюзивной блокировкой) - вы, вероятно, все еще можете написать сценарий для схемы таблицы, сделать ее MyTable2 - и затем продолжать писать запросы и возвращаться назад. и измените их, когда он закончится.

0 голосов
/ 26 ноября 2014

Аналогично, транзакция выполнялась, и пользователь отменил ее, заморозив SPID в KILLED \ ROLLBACK ... без изменения ввода / вывода.

Два других SPID были заблокированы этим SPID; которую я убил. Таким образом, разногласия по блокировкам были устранены, что позволило завершить откат.

Обратная логика - SPID, заблокированные SPID, блокируют откат SPID.

SQL для вас:)

...