SQL Server не може скинути базу даних <ім'я_d>, оскільки вона наразі використовується…, але сеанси не відображаються


72

Коли я намагаюся скинути базу даних, я отримую помилку "Неможливо скинути базу даних" dbname ", оскільки вона зараз використовується". Однак, коли я запускаю sp_who2, до цієї бази даних, безумовно, немає жодних сеансів. Я також встановив базу даних single_user mode with rollback immediate.

Чому це відбувається?

Відповіді:


20

Переконайтеся, що у вас немає залежностей, таких як знімки бази даних на db, який ви хочете видалити. Хоча повідомлення про помилку виглядало б інакше. Ви впевнені, що не існує прихованого процесу, який підключається до вашої бази даних? Хорошим підходом було б запуск сценарію, який вбиває всі сеанси та одразу після перейменування бази даних на інше ім'я, а потім скидання бази даних.

створити курсор на основі цього вибору:

  select  d.name , convert (smallint, req_spid) As spid
      from master.dbo.syslockinfo l, 
           master.dbo.spt_values v,
           master.dbo.spt_values x, 
           master.dbo.spt_values u, 
           master.dbo.sysdatabases d
      where   l.rsc_type = v.number 
      and v.type = 'LR' 
      and l.req_status = x.number 
      and x.type = 'LS' 
      and l.req_mode + 1 = u.number
      and u.type = 'L' 
      and l.rsc_dbid = d.dbid 
      and rsc_dbid = (select top 1 dbid from 
                      master..sysdatabases 
                      where name like 'my_db')

питання всередині курсору:

SET @kill_process =  'KILL ' + @spid      
            EXEC master.dbo.sp_executesql @kill_process
                   PRINT 'killed spid : '+ @spid

після закриття та розміщення курсору:

sp_dboption 'my_db', 'single user', 'TRUE'

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 

Дякуємо за код - який може працювати. Що я не розумію, що це "прихований" сеанс? Я б подумав, що sp_who та інші метадані (DMV) показуватимуть усі сеанси, інакше, чим вони користуються?
тузо

Так, зазвичай, ви повинні мати можливість бачити всіх активних / неактивних через sp_who або запитувати таблицю sysprocess з головного db. Під прихованим я мав на увазі процес, який знову підключається до служби додатків. Ура.
yrushka

1
Це антикваріат з кількох причин: (1) старий стиль приєднується (2) зворотні погляди сумісності (3) курсор і динамічний SQL для запуску кулі команд KILL, коли один ALTER буде виконувати (4) застарілі процедури, такі як sp_dboption.
Аарон Бертран

1
На жаль, я не думаю, що це відповідає на питання - запитуючий запитує, чому це відбувається, а не як вирішити. Надана відповідь працює, але я досі не знаю, що заважає мені видалити базу даних. @AaronBertrand згадав "винуватцем навіть« Об’єктний Провідник », який насправді став причиною ОДИН із баз даних, але як я можу сказати, що це« Провідник об’єктів »?
LearnByReading

це дає мені помилку "Не вдається використати KILL, щоб вбити власний процес"
nuander

80

Сеанс, підключений до іншої бази даних, може мати відкриту транзакцію, яка також впливає на вашу базу даних - sp_who2 покаже лише одну базу даних. Це також може бути таким простим, як Object Explorer або Object Explorer Details, відкриті в SSMS, що знову б показувало лише одну базу даних у sp_who2.

Не переймайтеся намаганням знайти відповідальний сеанс; просто вбийте їх всім одним твердженням (і переконайтеся, що не підключена ваша копія SSMS, наприклад, інше вікно запитів, Провідник об’єктів тощо):

USE master;
GO
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

Тепер ви зможете скинути його та зробити це за допомогою DDL, а не інтерфейсу користувача:

DROP DATABASE dbname;

1
Дякую за вашу відповідь, це спрацювало. Але мені просто важко жити з цим рішенням: чому я не можу скинути деякі бази даних через цю помилку? У мене є кілька баз даних, які не торкалися протягом року, і жодного процесу чи нібито транзакції, які би не були пов'язані з ними. Чи можете ви дати мені підказки, які допоможуть мені знайти потенційні послуги, транзакції чи щось, що пов'язано з цими базами даних?
LearnByReading

1
На насправді, все , що я повинен був зробити USE master, то DROP DATABASE dbname. Мабуть, все, що потрібно, це просто "використовувати" щось інше, щоб звільнити db.
vapcguy

2
@vapcguy Це справедливо лише в тому випадку, якщо у вашому поточному вікні запитів є єдине з'єднання. Зазвичай це не так (і саме тому в моїх відповідях зазначено "і переконайтеся, що це не ваша копія SSMS, яка пов'язана").
Аарон Бертран

20

Яка ваша поточна база даних при видачі DROPкоманди? Спробуйте це:

use master
go
drop database mydb
go

Також переконайтеся, що ви підключені як до, так saі не dboдо тієї бази даних, яку ви хочете залишити.


Я напевно пов'язаний з майстром. Мені не потрібно було підключатись, як щоб скинути базу даних. Мені це здається помилкою - це не відображення сеансу, або він вважає, що використовується сесія, але її немає.
тузо

3
Я щойно з цим захопився - спробував запустити сценарій drop з контекстом, встановленим до бази даних, із запиту sqlcmd! Doh
JonnyRaa

18

Як щодо того, щоб просто побачити, що робить SSMS, коли ви користуєтесь інтерфейсом, але скажіть йому, щоб видати сценарій для дії? Ось що робить SSMS, коли клацніть правою кнопкою миші БД та виберіть Видалити, а потім встановіть прапорець, щоб закрити наявні з'єднання:

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'yourdbname'
GO

USE [master]
GO
ALTER DATABASE [yourdbname] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

USE [master]
GO

DROP DATABASE [yourdbname]
GO

... якщо припустити, звичайно, це нормально, щоб
відкатати

4
Ви скидаєте базу даних, я вважаю, що це цілком гаразд.
georgiosd

1
Це працювало для мене! :)
Леонардо Тримарчі

5

Я неодноразово стикався з цією ситуацією і нижче, що я роблю:

Коли очевидні методи не діють ..... (як у вашій ситуації):

Дізнайтеся ідентифікатор бази даних із системних баз даних.

Потім виконати - sp_lockщо покаже всі блоки на екземплярі разом із spid та dbid.

Вбийте павуків, які ви намагаєтесь відключити або відкинути.

Хоча процес трохи ручний, його можна автоматизувати, як показано нижче:

IF OBJECT_ID('tempdb.dbo.#temp', 'U') IS NOT NULL
  DROP TABLE #temp;
create table #temp (spid int
                , dbid int
                ,ObjId bigint
                , IndId bigint
                ,Type varchar(5)
                ,resource varchar(max)
                ,Mode varchar(5)
                ,status varchar(10));
declare @dbid int
select @dbid =DB_ID(db_name())

insert into #temp
exec sp_lock

select * from #temp
where dbid = @dbid

2

Знайшов дійсно просту відповідь на StackOverflow, який працював для мене вперше:

https://stackoverflow.com/a/7469167/261405

Ось SQL з цієї відповіді:

DECLARE @DatabaseName nvarchar(50)
SET @DatabaseName = N'YOUR_DABASE_NAME'

DECLARE @SQL varchar(max)

SELECT @SQL = COALESCE(@SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(@DatabaseName) AND SPId <> @@SPId

--Use this to see results
SELECT @SQL 
--Uncomment this to run it
--EXEC(@SQL)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.