Which SQL sentence (function or stored procedure) I can use to monitor an SQL Server DeadLock, caused by an UPDATE statement?
try this query to see blocking processes, including the actual SQL query text:
SELECT
r.session_id AS spid
,r.cpu_time,r.reads,r.writes,r.logical_reads
,r.blocking_session_id AS BlockingSPID
,LEFT(OBJECT_NAME(st.objectid, st.dbid),50) AS ShortObjectName
,LEFT(DB_NAME(r.database_id),50) AS DatabaseName
,s.program_name
,s.login_name
,OBJECT_NAME(st.objectid, st.dbid) AS ObjectName
,SUBSTRING(st.text, (r.statement_start_offset/2)+1,( (CASE r.statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE r.statement_end_offset
END - r.statement_start_offset
)/2
) + 1
) AS SQLText
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text (sql_handle) st
--WHERE r.session_id!=##SPID --uncomment to not see this query
deadlocks are easily trapped with the profiler:
Try running the run a trace in the profiler (pick the blank template), select the "deadlock graph event", and on the new tab that appears (Events Extraction Settings), save each (check "save deadlock XML events separately") in its own file. Open this file in an xml viewer and it will be easy to tell what is happening. Each process is contained, with an execution stack of procedure/trigger/etc calls, etc. and all locks are in there too.
Look at the "resource list" section of the file, it will show what is being locked and held by each process causing the deadlock. Figure out how to not have one of these locked and the deadlock will be resolved.
Let this trace run until the deadlock happens again, info is only recorded when a deadlock happens, so there isn't much overhead. If it never happens again, good it is solved, if not you have captured all the info.
I think you're better placed to use SQL Profiler to monitor deadlocks - see here. SQL Profiler shows the deadlocks in a diagram to make it easier to determine what caused them.
SELECT * FROM sys.dm_exec_requests WHERE blocking_session_id <> 0
But that will show you requests that are blocking, which is normal for SQL Server and doesn't indicate a deadlock. If SQL Server detects a deadlock it will kill one of the processes to allow the others to continue. So you can't use a function or stored procedure to monitor this as by the time it happens it has already finished.
You can either use the SQL Profiler or Trace Flags
Related
So, I have been looking into more SQL server management tools using a few of them, and I have been amazed to find simple selects blocking themselves and causing deadlocks. I have done a little research, but I am truly amazed this could happen. Can anyone clarify, or maybe solve, why this happens?
I'm talking about a simple select.
SELECT
ID
FROM
MainTable
WHERE
Name Like 'John Smith'
Using Microsoft SQL Server Managment Studios, if it matters.
In SQL 2000 processes would sometimes report as blocking themselves, but I don't think this applies in later versions of SQL Server.
latch waits reported as blocking
It is definitely possible for a SELECT statement to cause a deadlock, because shared locks are acquired when data is selected, but there would also have to be another process that is trying to update the data.
A parallel execution plan can show as a SPID blocking itself. This is basically just threads waiting for the other tasks in the query to complete. Deadlocking is another matter, caused by different sessions waiting on each other. Deadlocks (and excessive parallelism) can be a symptom of the need for query and index tuning.
If you are running SQL 2008 or later, deadlock information is captured by the system_helath extended event trace by default. Below is a query to extract recent deadlock information from the ring buffer. This will eliminate some of the guesswork.
SELECT
xed.value('#timestamp', 'datetime') as Creation_Date,
xed.query('.') AS Extend_Event
FROM
(
SELECT CAST([target_data] AS XML) AS Target_Data
FROM sys.dm_xe_session_targets AS xt
INNER JOIN sys.dm_xe_sessions AS xs
ON xs.address = xt.event_session_address
WHERE xs.name = N'system_health'
AND xt.target_name = N'ring_buffer'
) AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[#name="xml_deadlock_report"]') AS XEventData(xed)
ORDER BY Creation_Date DESC;
This simple select cannot deadlock itself, the only possible cause is something else is updating/deleting rows while you are reading.
Try launching SQL Server Profiler and use the:
deadlock
deadlock chain
deadloch graph
events in your template.
The Deadlock graph in particular will help you identify which two processes are causing trhe deadlock and the one chosen as deadlock victim
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Help with deadlock in Sql Server 2008
SQLServer automatically logs all deadlocks. Can anyone help me to get sql query which will capture deadlocks data that is being collected, for a recent event.
I am using SQL SERVER 2008 R2 for my development activities.
Thanks & Regards,
Santosh Kumar Patro
You can use a deadlock graph and gather the information you require from the log file.
The only other way I could suggest is digging through the information by using EXEC SP_LOCK (Soon to be deprecated), EXEC SP_WHO2 or the sys.dm_tran_locks table.
SELECT L.request_session_id AS SPID,
DB_NAME(L.resource_database_id) AS DatabaseName,
O.Name AS LockedObjectName,
P.object_id AS LockedObjectId,
L.resource_type AS LockedResource,
L.request_mode AS LockType,
ST.text AS SqlStatementText,
ES.login_name AS LoginName,
ES.host_name AS HostName,
TST.is_user_transaction as IsUserTransaction,
AT.name as TransactionName,
CN.auth_scheme as AuthenticationMethod
FROM sys.dm_tran_locks L
JOIN sys.partitions P ON P.hobt_id = L.resource_associated_entity_id
JOIN sys.objects O ON O.object_id = P.object_id
JOIN sys.dm_exec_sessions ES ON ES.session_id = L.request_session_id
JOIN sys.dm_tran_session_transactions TST ON ES.session_id = TST.session_id
JOIN sys.dm_tran_active_transactions AT ON TST.transaction_id = AT.transaction_id
JOIN sys.dm_exec_connections CN ON CN.session_id = ES.session_id
CROSS APPLY sys.dm_exec_sql_text(CN.most_recent_sql_handle) AS ST
WHERE resource_database_id = db_id()
ORDER BY L.request_session_id
http://www.sqlmag.com/article/sql-server-profiler/gathering-deadlock-information-with-deadlock-graph
http://weblogs.sqlteam.com/mladenp/archive/2008/04/29/SQL-Server-2005-Get-full-information-about-transaction-locks.aspx
In order to capture deadlock graphs without using a trace (you don't need profiler necessarily), you can enable trace flag 1222. This will write deadlock information to the error log. However, the error log is textual, so you won't get nice deadlock graph pictures - you'll have to read the text of the deadlocks to figure it out.
I would set this as a startup trace flag (in which case you'll need to restart the service). However, you can run it only for the current running instance of the service (which won't require a restart, but which won't resume upon the next restart) using the following global trace flag command:
DBCC TRACEON(1222, -1);
A quick search yielded this tutorial:
Finding SQL Server Deadlocks Using Trace Flag 1222
Also note that if your system experiences a lot of deadlocks, this can really hammer your error log, and can become quite a lot of noise, drowning out other, important errors.
Have you considered third party monitoring tools? SQL Sentry and Plan Explorer, for example, have a much nicer deadlock graph, showing you object / index names, as well as the order in which the locks were taken. As a bonus, these are captured for you automatically on monitored servers without having to configure trace flags, run your own traces, etc.:
New Deadlock Visualizations in SQL Sentry and Plan Explorer
Analyzing Deadlocks in SQL Sentry
Disclaimer: I used to work for SQL Sentry.
Running the following simple query in SSMS:
UPDATE tblEntityAddress
SET strPostCode= REPLACE(strPostCode,' ','')
The update to the data (at least in memory) is complete in under a minute. I verified this by performing another query with transaction isolation level read uncommitted. The update query, however, continues to run for another 30 minutes. What is the issue here? Is this caused by a delay to write to disk?
TIA
Most probably, you transaction is locked by another transaction which affected tblEntityAddress.
Run sp_lock and see if tblEntityAddress is locked by another process.
In a separate SSMS window, try running the following:
SELECT status, wait_type
FROM sys.dm_exec_requests
WHERE session_id = <SPID>
Just replaced with the SPID associated with your UPDATE query (number in brackets after your login name in the bottom bar).
Run the above a few times in succession and note what the wait_type is. There are numerous types of waits - see what that is (& let use know), it could highlight the cause.
Update:
Quotes from this MS KB article:
IO_COMPLETION
This waittype indicates that the SPID
is waiting for the I/O requests to
complete. When you notice this
waittype for an SPID in the
sysprocesses system table, you must
identify the disk bottlenecks by using
the performance monitor counters,
profiler trace, the
fn_virtualfilestats system
table-valued function, and the
SHOWPLAN option to analyze the query
plans that correspond to the SPID. You
can reduce this waittype by adding
additional I/O bandwidth or balancing
I/O across other drives. You can also
reduce I/O by using indexing, look for
bad query plans, and look for memory
pressure.
Another thing to consider is a slow running trigger.
I have two databases on one SQL 2008 server. Database 1 seems to be causing a lock on a table on database 2. There no queries are running on database 1 that should affect database 2.
Is this normal behaviour?
When I view the running queries with this command
SELECT sqltext.TEXT,
req.session_id,
req.status,
req.command,
req.cpu_time,
req.total_elapsed_time/1000 [seconds]
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext
it tells me as much, and says that the command on database 2 is suspended.
I'm at a bit of a loss. What sort of things should I look at to work out why the table in database 2 is locked?
Queries running are irrelevant - the lock can be from a query that DID run and the connection / transaction is still valid (i.e. open transaction, not commited / rolled back), in which case the lock stays in place.
You basically have to identiy:
The connection that locks the table.
THe command chain run there within the connection.
Locks originate from operations the db does - so unless you got a low level critical error (VERY unlikely with an error like that) something has caused the lock to be generated.
I have a SQL statement from my application. I'd like to know which locks that statement acquires; how can I do that with SQL server?
The statement has been involved in a deadlock, which I'm trying to analyze; I cannot reproduce the deadlock.
I'm running on MS SQL Server 2005.
You can run the statement in a transaction, but not commit the transaction. Since the locks will be held until the transaction is committed, this gives you time to inspect the locks. (Not indefinitely, but like 5 minutes by default.)
Like:
BEGIN TRANSACTION
select * from table
Then open Management Studio and check the locks. They're in Management -> Activity Monitor -> Locks by Object or Locks by Process. After you're done, run:
COMMIT TRANSACTION
to free the locks.
I would suggest that you turn on the Deadlock Detection Trace Flags in the first instance, rather than running a Profiler Trace indefinitely.
This way, the event details will be logged to the SQL Server Error Log.
Review the following Books Online reference for details of the various trace flags. You need to use 1204 and/or 1222
http://msdn.microsoft.com/en-us/library/ms188396(SQL.90).aspx
Be sure to enable the trace flags with server scope and not just the current session. For example use:
DBCC TRACEON(1222,-1)
Here's a query that will show you all active locks, who's got them, and what object they are on. I pulled this from a technet article or something years and years ago. It works on SQL 2000 and 2005 (change sysobjects to sys.objects for 2005.) Uncomment the WHERE clause if you want to restrict it to just this databse, and just the "EXCLUSIVE" locks.
select 'Locks' as Locks,
spid, nt_username, name, hostname, loginame, waittime, open_tran,
convert(varchar ,getdate() - last_batch, 114) as TimeSinceLastCommand,
case req_mode
when 0 then 'Not granted'
when 1 then 'Schema stability'
when 2 then 'Schema modification'
when 3 then 'Intent shared'
when 4 then 'Shared intent update'
when 5 then 'Intent shared shared'
when 6 then 'Intent exclusive'
when 7 then 'Shared Intent Exclusive'
when 8 then 'Shared'
when 9 then 'Update'
when 10 then 'Intent insert NULL'
when 11 then 'Intent shared exclusive'
when 12 then 'Intent update'
when 13 then 'Intent shared-update'
when 14 then 'Exclusive'
when 15 then 'Bulk operation'
else str(req_mode) end as LockMode
from master..syslockinfo
left join sysobjects so on so.id = rsc_objid
left join master..sysprocesses sp on sp.spid = req_spid
--where rsc_dbid = (select db_id()) and ltrim(req_mode) in (6,7,11,14)
run a trace in the profiler (pick the blank template), select the deadlock graph event, and on the new tab that appears (Events Extraction Settings), save each (check save deadlock XML events separately) in its own file. Open this file in an xml viewer and it will be easy to tell what is happening. Each process is contained, with a stack of procedure calls, etc. and all locks are in there too.
Let this trace run until the deadlock happens again, info is only recorded when a deadlock happens, so not much overhead. If it never happens again, good it is solved, if not you have captured all the info.
You can run a profiler trace on your dev box for the queries and see exactly what locks are taken. This is typically a huge amount of data, but much of it will be patterns you can skim over. E.g. for read committed isolation, you will see a succession of locks being acquired and released as you do a table or index scan (each row must be locked before it is read, and it is immediately released after it is read).
What isolation do you run under? What kind of queries are deadlocking? Are you using explicit transactions that encompass multiple updates, or are they single statements deadlocking?
The most typical case for a deadlock is a transaction with the sequence (update table x, update table y), and a second transaction with the sequence (update table y, update table x). The common solution is to make sure you use the same update sequence across queries.
Let us know what kind of queries they are, there are different common issues for different types of transactions.
Troubleshooting deadlocks:
http://blogs.msdn.com/bartd/archive/2006/09/09/747119.aspx
http://blogs.msdn.com/bartd/archive/2006/09/13/751343.aspx
Reproducing deadlocks:
http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx