Test Before Attempting Exclusive Lock - sql-server

I've written some code to upgrade a SQL Server database. Before I upgrade the database, I attain an exclusive lock via:
ALTER DATABASE Test SET SINGLE_USER WITH NO_WAIT
However, I'd like to test the database to see if the exclusive lock is possible before I run the above code. The test doesn't have to be 100% perfect, I'd just like to avoid the possibility of a timeout when attempting to gain an exclusive lock.
To that end, I've written the code below:
SELECT
*
FROM
sys.db_tran_locks
WHERE
resource_database_id = DB_ID('Test') AND
request_session_id <> ##SPID
I'm assuming that if there's 1 or more row returned, then the database must be in use. Is this true? Or is it not that simple?
UPDATE Taking #gbn's comments into account, I've decided to force rollback of existing connections using the following statement:
ALTER DATABASE Test SET SINGLE_USER WITH ROLLBACK IMMEDIATE
Before running this code, I'll give the user the an opportunity to opt out. However, I'd like the user to be able to see the list of active connections to the database - so they can make an informed decision. Which leads me onto this question.

Mainly, a DB lock is just to show it is in use. Databases don't really have many exclusive locks situations compared to code/table objects.
Single user mode is not a lock, but the number of connections allowed.
I'd wrap the ALTER DATABASE in a TRY/CATCH block because there is no guarantee the state won't change between check and ALTER DB.
However, I could be wrong or misunderstanding the question... so you'll also have to test for the exclusive lock mode on the database resource in the query above. Your code above will show you any lock, which could be someone having a blank query window open in SSMS...
Edit, based on comment
You can detect who is using it by these:
sys.dm_exec_connections
sys.dm_exec_sessions
sys.dm_exec_requests
To be honest, it's difficult to stop auto stats update or a user taking the single connection. Normally, you'd this which disconnects all other users and not bother waiting...
ALTER DATABASE MYDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE

What if the database becomes busy from the time you determined that it was not in use, until the point where you try to acquire the exclusive lock?

Related

SQL Job Agent DB Restore fails with error #6107: Only user processes can be killed

We have an SQL Job Agent that runs in the "wee hours" to restore our local database (FooData) from a production backup.
First, the database is set to SINGLE_USER mode and any open processes are killed. Second, the database is restored.
But the 3rd step fails occasionally with Error 6107: "Only User Processes Can Be Killed"
This happens about once or twice a week at seemingly random intervals. Here is the code for step 3 where the failure occasionally occurs:
USE master;
go
exec msdb.dbo.KillSpids FooData;
go
ALTER DATABASE FooData SET MULTI_USER;
go
Does anybody have any ideas what might be occurring to cause this error? I'm thinking there might be some automated process starting up during step 3 or possibly some user trying to log in during that time? I'm not a DBA, so I'm guessing at this point, although I believe that a user should not be able to log in while the DB is in SINGLE_USER mode.
A user probably isn't logged in. The system is probably performing some task. The output of exec sp_who or sp_who2 will show what sessions are open. Any SPID below 50 is a system process, and cannot be killed with KILL. The only way to stop them is to stop the SQL Server service or issue a SHUTDOWN command (which does the same thing).
I found the answer to my problem by changing one line of code which worked like a charm.
As mentioned in the original question, the 'KillSpids" line is used in Step 1 of the job. (Along with SET SINGLE USER) The 'KillSpids' made sense in Step 1 because there may be unwanted processes still active on the database.
The 'KillSpids' line was then added again into Step 3, but it was unnecessary, and was also causing the 6107 error.
I replaced the 'KillSpids' line with the one shown below. Setting the freshly restored database to single user mode takes care of the concern that a user might try to log in before all the job steps have been completed. Here is the updated code:
USE master;
go
ALTER DATABASE [FooData] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
go
ALTER DATABASE FooData SET MULTI_USER;
go

Kill user process

Currently, i have SQL Server 2005 database for which I have admin rights, but do not have sysadmin rights.
There was a particular process which was stopping me to do few things on a table.
Is there a way to kill a user SQL queries, if they were ran through a web client without having sys admin rights. In my case, django website ran the query using pymssql ?
Using "KILL" is role-restricted for a very good reason, and should be used only when you understand what the blocking process is doing. If the KILL statement is used against a SPID executing a long-running transaction, the KILL will initiate a ROLLBACK on the table (which can take quite a while on a large table) to maintain DB consistency. The statement:
SELECT open_tran FROM master.sys.sysprocesses WHERE SPID=<blocking SPID number>
will give you some detail about the process and what it's doing. Alternatively you can try:
DBCC INPUTBUFFER(<spid>)
to find the last statement that was submitted by a SPID (though I think your permissions might not be sufficient). If it's determined that the SPID is sleeping on the block, you'll still need to be promoted to a minimum role of processadmin in order to execute a KILL statement.
Three other recommendations to help you:
Work to implement the use of Locking Hints in code executed against the DB.
If this is a consistent problem, ask your DBA's to evaluate the statement(s) that cause the blocks, and ask their advice.
Getting close to your DBAs never hurts, and a little buttering up (pizza lunch, after-work drinks, etc.) once or twice can really make a difference. They may not grant you the permission promotion you need, but they could create a workaround for you as described here that could solve your problem without changing your role.
Use command for see connections sp_who then use command KILL <SPID>
if you are using ssms then try to close/save the editor window where you sp or query started running
ssms will ask you to commit the transaction just press ok
That's it!

SQL Server tells me database is in use but it isn't

SQL Server keeps telling me a database is in use when I try to drop it or restore it, but when I run this metadata query:
select * from sys.sysprocesses
where dbid
in (select database_id from sys.databases where name = 'NameOfDb')
It returns nothing.
Sometimes it will return 1 process which is a CHECKPOINT_QUEUE waittype. If I try to kill that process, it won't let me (cannot kill a non-user process).
Anyone have any idea what's wrong?
i like this script. Do not struggle with killing..
use master
alter database xyz set single_user with rollback immediate
restore database xyz ...
alter database xyz set multi_user
I was having the same issue when trying to restore a database from a backup. The solution for me was to ensure that I checked "Overrite the existing database(WITH REPLACE)" and "Close existing connections to destination database" in the Options page BEFORE doing the restore. Here is a screenshot below.
There could be lots of things blocking your database. For example, if you have a query window opened on that database, it would be locked by you. Not counting external accesses, like a web application on IIS.
If you really wanna force the drop on it, check the close existing connections option or try to manually stop SQL Server's service.

DML operation with out logging - SQL Server

Is there any way that we can do DML operation with out logging it into log file?
For example, when I am inserting a row in database, this operation will be logged in log file irrespective of using transaction or not. But I don't want to log this operation in the log file.
No. Never. Not possible.
Every operation is logged for a reason: what if it fails halfways through? Server crashes? etc etc
In summary: the A, C and D in ACID
If you don't want this, then using I would really consider using non-ACID NoSQL alternatives.
SQL Server will always write an insert to the log file. It needs that information to recover a database in a consistent state when the server resets.
You can change to impact logging has by choosing the recovery model:
alter database YourDb set recovery { FULL | BULK_LOGGED | SIMPLE }
In simple mode, SQL Server logs just running transactions, and starts reusing parts of the log that are no longer needed. In simple mode, the log file typically remains small.
If you want to get rid of logs after an insert operation, you can use:
alter database YourDb set recovery simple with no_wait
dbcc shrinkfile(YourDbLog, 1)
alter database YourDb set recovery <<old model here>>
Note that this gets rid of all logs. You can only use the restore the last full backup after running this command.

How to delete database, error 5030 database can't be locked

I am trying to delete an existing database in SQL Server 2005. My first attempt produced the following error:
5030: The database could not be exclusively
locked to perform the operation.
I have since killed all processes that are accessing the database. I have also removed the replication subscription that it had previously been involved in.
Any thoughts on what else that could be holding the lock on it besides SQL Server processes and replication?
Update: I restarted the server, and that fixed it. I was trying to avoid that, since this is a production server, but hey what can you do?
A production server in which so many connections use the database yet you want to drop it? :)
None the less, how to kick out everybody from the database:
USE [dbname];
ALTER DATABASE [dbname] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
Then drop the database:
USE [master];
DROP DATABASE [dbname];
There is still a very small window of opportunity between the USE [master]; and DROP DATABASE ... where some other connection can grab the 1 single allowed lock on the database, but it usually not worth working around that.
I hate to say it, but a quick solution is to restart the system, make sure the sql server server service is not started, then you should be able to delete.
Also, is IIS stopped if you db is connected to a web ap?
You don't happen to know if anyone left a transaction in an uncompleted rollback state (or otherwise uncompleted)? Might as well check the locks list, too.
In the management studio, goto Management->Activity Monitor (right click) -> View Processes. That will give you a full list of everything running, you can sort the list by Database to see what is still attached, and you can also kill any connections. It's easy to end up with orphaned connections that will prevent you from getting the exclusive access that you need.
No One else should be using the DB, including yourself.
Why would we make a deleted DB to multi user mode.
ALTER DATABASE dbName SET MULTI_USER WITH ROLLBACK IMMEDIATE
To avoid this error, use the T-SQL script below in the master database. Make sure to run this (and modify the #dbname) for each database you are running the ALTER DATABASE command in.
"The database could not be exclusively locked to perform the
operation"
This "connection killer" script will work if Windows has established JDBC connections to the database. But this script is unable to kill off JDBC connections for Linux services (e.g. JBoss). So you'll still get that error if you don't stop JBoss manually. I haven't tried other protocols, but please comment if you find out more information as you build new systems.
USE master;
DECLARE #dbname sysname
Set #dbname = 'DATABASE_NAME_HERE-PROD'
Declare #spid int
Select #spid = min(spid) from master.dbo.sysprocesses
where dbid = db_id(#dbname)
While #spid Is Not Null
Begin
Execute ('Kill ' + #spid)
Select #spid = min(spid) from master.dbo.sysprocesses
where dbid = db_id(#dbname) and spid > #spid
End
This error normally occurs when your database is in Multi User mode where users are accessing your database or some objects are referring to your database.
First you should set the database to single user mode:
ALTER DATABASE dbName
SET SINGLE_USER WITH ROLLBACK IMMEDIATE
Now we will try to delete the database
delete DATABASE ...
Finally set the database to Multiuser mode
ALTER DATABASE dbName
SET MULTI_USER WITH ROLLBACK IMMEDIATE

Resources