Репро
- Відкрийте SSMS
Введіть наступне у нове вікно запитів
use <YourDatabase>;
go
- Перейдіть до Провідника об’єктів (SSMS) і клацніть правою кнопкою миші на
<YourDatabase>
-> Tasks
->Take Offline
Відкрийте друге вікно нового запиту та введіть таке:
use <YourDatabase>;
go
Вам буде запропоновано таке повідомлення:
Msg 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;
Для того, що це варто, вам не потрібен Провідник об’єктів для відтворення цієї помилки. Вам просто потрібен заблокований запит, який намагається здійснити ту саму операцію (у цьому випадку перенесіть базу даних в офлайн). Дивіться скріншот нижче трьох кроків у T-SQL:
Що ви, швидше за все, побачите, це ваш сеанс Провідника об’єктів заблокований іншим сеансом (показано на blocking_session_id
). Цей сеанс Провідника об’єктів намагатиметься отримати ексклюзивний замок ( X
) на базі даних. У наведеному вище випадку запиту сесії Object Explorer було надано блокування оновлення ( U
) та спроба перетворення в ексклюзивний замок ( X
). Він мав тип очікування LCK_M_X
, заблокований нашим сеансом, який був представлений першим вікном запиту ( use <YourDatabase>
хапає спільний замок ( S
) в базі даних).
А потім ця помилка виникла в результаті ще однієї сесії, яка намагається отримати блокування, і це повідомлення про помилку призводить до відмови в сеансі для отримання доступу до бази даних, яка намагається перейти в інший стан (у цьому випадку стан онлайн до офлайн переходу).
Що робити наступного разу?
По-перше, не панікуйте і не починайте скидати бази даних . Вам потрібно скористатися підходом до усунення несправностей (з аналогічним діагностичним запитом, як у наведеному вище), щоб з’ясувати, чому ви бачите те, що бачите. З таким повідомленням або коли щось з’являється «висіло», вам слід автоматично припустити відсутність одночасності і почати розкопуватися на блокування ( sys.dm_tran_locks
це хороший старт).
Як зауваження, я справді вважаю, що вам найкраще з’ясувати корінь проблеми, перш ніж робити будь-які випадкові дії. Не тільки з цією операцією, але це стосується всієї поведінки, якої ви не очікуєте. Знаючи, що насправді спричиняло вашу проблему, очевидно, що насправді це не було великою справою. У вас в основному був ланцюг блокування, і батьківський блокатор був чимось, на що ви, ймовірно, могли щойно випустити KILL
, або якщо це був запит сеансу, якого ви не хотіли, KILL
тоді ви могли дочекатися його завершення. У будь-якому випадку, ви мали б знання, щоб прийняти правильне та розсудливе рішення, враховуючи ваш конкретний сценарій (відкат або чекайте на виконання зобов’язань).
Ще одна річ, яку варто зазначити, це одна з причин, чому я завжди вибираю альтернативу T-SQL замість GUI. Ви точно знаєте, що виконуєте за допомогою T-SQL і що робить SQL Server. Зрештою, ви видали явну команду. Під час використання графічного інтерфейсу фактичний T-SQL стане абстракцією. У цьому випадку я переглянув спробу заблокованого Провідника Об’єктів зняти базу даних в автономному режимі ALTER DATABASE <YourDatabase> SET OFFLINE
. Не було спроби відкату, через що її чекали нескінченно. У вашому випадку, якби ви хотіли відмовити сеанси, які мали блокування в цій базі даних, вам ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
, швидше за все, було б достатньо, якби ви попередньо визначили, що відкат був у порядку.