репродукция
- Откройте SSMS
Введите следующее в новом окне запроса
use <YourDatabase>;
go
- Перейдите к Обозревателю объектов (SSMS) и щелкните правой кнопкой мыши
<YourDatabase>
-> Tasks
->Take Offline
Откройте второе новое окно запроса и введите следующее:
use <YourDatabase>;
go
Вам будет предложено следующее сообщение:
Сообщение 952, уровень 16, состояние 1, строка 1
База данных «TestDb1» находится в процессе перехода. Попробуйте утверждение позже.
Причина, по которой это происходит, может быть найдена из диагностического запроса, аналогичного приведенному ниже:
select
l.resource_type,
l.request_mode,
l.request_status,
l.request_session_id,
r.command,
r.status,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.wait_resource,
request_sql_text = st.text,
s.program_name,
most_recent_sql_text = stc.text
from sys.dm_tran_locks l
left join sys.dm_exec_requests r
on l.request_session_id = r.session_id
left join sys.dm_exec_sessions s
on l.request_session_id = s.session_id
left join sys.dm_exec_connections c
on s.session_id = c.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st
outer apply sys.dm_exec_sql_text(c.most_recent_sql_handle) stc
where l.resource_database_id = db_id('<YourDatabase>')
order by request_session_id;
Для чего бы то ни было, вам не нужен Object Explorer, чтобы воспроизвести эту ошибку. Вам просто нужен заблокированный запрос, который пытается выполнить ту же операцию (в этом случае переведите базу данных в автономный режим). Смотрите на скриншот ниже для трех шагов в T-SQL:
Скорее всего, вы увидите, что ваш сеанс Object Explorer заблокирован другим сеансом (показано blocking_session_id
). Этот сеанс Object Explorer будет пытаться получить эксклюзивную блокировку ( X
) для базы данных. В приведенном выше случае воспроизведения, сеансу Object Explorer была предоставлена блокировка обновления ( U
) и была предпринята попытка преобразования в эксклюзивную блокировку ( X
). Он имел тип wait_type LCK_M_X
, заблокированный нашей сессией, который был представлен первым окном запроса ( use <YourDatabase>
захватывает общий замок ( S
) в базе данных).
И затем эта ошибка возникла из-за еще одного сеанса, пытающегося получить блокировку, и это сообщение об ошибке приводит к отказу сеанса в получении доступа к базе данных, которая пытается перейти в другое состояние (в данном случае, состояние онлайн в автономный переход).
Что делать в следующий раз?
Во-первых, не паникуйте и не начинайте удалять базы данных . Вам необходимо использовать метод устранения неполадок (с аналогичным диагностическим запросом, подобным приведенному выше), чтобы выяснить, почему вы видите то, что видите. С таким сообщением или когда что-то кажется «зависшим», вы должны автоматически предположить отсутствие параллелизма и начать копаться в блокировке ( sys.dm_tran_locks
это хорошее начало).
В качестве примечания, я действительно верю, что вам лучше всего выяснить причину проблемы, прежде чем предпринимать какие-либо случайные действия. Не только с этой операцией, но и с поведением, которое вы не ожидаете. Зная, что на самом деле стало причиной вашей проблемы, очевидно, что это не было большой проблемой. По сути, у вас была цепочка блокировок, и родительский блокировщик - это то, что вы, скорее всего, могли бы просто выдать KILL
, или, если это был запрос сеанса, который вы не хотели бы делать, KILL
вы могли бы дождаться его завершения. В любом случае, у вас были бы знания, чтобы принять правильное и разумное решение с учетом вашего конкретного сценария (откат или ожидание коммита).
Стоит отметить еще одну вещь: это одна из причин, по которой я всегда выбираю альтернативу T-SQL вместо графического интерфейса. Вы точно знаете, что вы выполняете с T-SQL и что делает SQL Server. В конце концов, вы дали явную команду. Когда вы используете GUI, фактический T-SQL будет абстракцией. В этом случае я посмотрел на попытку заблокированного обозревателя объектов перевести базу данных в автономный режим, и это было так ALTER DATABASE <YourDatabase> SET OFFLINE
. Не было попыток отката, поэтому он ждал бесконечно долго. В вашем случае, если вы хотите откатить сеансы с блокировками в этой базе данных, ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
скорее всего , вам будет достаточно, если вы вначале определили, что откат был в порядке.