您的位置:首页 > 数据库

(Reprint) Find out and fixing deadlock by sql server 2005 immediately

2009-07-06 19:00 507 查看

reprint from: http://weblogs.sqlteam.com/mladenp/archive/2008/05/21/SQL-Server-2005-Immediate-Deadlock-notifications.aspx

This article is focusing on about using Sql Server 2005's features to find out and handling deadlock problems.1, Try Catch2, After Catch Exception, checking
XACT_STATE() = -1 // transaction has uncommitted
3, After that then checking
ERROR_NUMBER() = 1205 // deadlock
Deadlocks can be a pain to debug since they're so rare andunpredictable. The problem lies in repeating them in your devenvironment. That's why it's crucial to have as much information aboutthem from the production environment as possible.There are two ways to monitor deadlocks, about which I'll talk aboutin the future posts. Those are SQL Server tracing and Error logchecking. Unfortunately both of them suffer from the same thing: youdon't know immediately when a deadlock occurs. Getting this info assoon as possible is sometimes crucial in production environments. Sureyou can always set the trace flag 1222 on, but this still doesn't solvethe immediate notification problem.One problem for some might be that this method is only truly usefulif you limit data access to stored procedures. <joke> So all youORM lovers stop reading since this doesn't apply to you anymore!</joke>The other problem is that it requires a rewrite of the problematicstored procedures to support it. However since SQL Server 2005 came outmy opinion is that every stored procedure should have the try ... catchblock implemented. There's no visible performance hit from this and thebenefits can be huge. One of those benefits are the instant deadlockingnotifications.Needed "infrastructure"So let's see how it done. This must be implemented in the database you wish to monitor of course.First we need a view that will get lock info about the deadlock thatjust happened. You can read why this type of query gives info we needin my previous post.CREATE VIEW vLocksASSELECT 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 TransactionNameFROM sys.dm_tran_locks LLEFT JOIN sys.partitions P ON P.hobt_id = L.resource_associated_entity_idLEFT JOIN sys.objects O ON O.object_id = P.object_idLEFT JOIN sys.dm_exec_sessions ES ON ES.session_id = L.request_session_idLEFT JOIN sys.dm_tran_session_transactions TST ON ES.session_id = TST.session_idLEFT JOIN sys.dm_tran_active_transactions AT ON TST.transaction_id = AT.transaction_idLEFT JOIN sys.dm_exec_requests ER ON AT.transaction_id = ER.transaction_idCROSS APPLY sys.dm_exec_sql_text(ER.sql_handle) AS STWHERE resource_database_id = db_id()GONext we have to create our stored procedure template:CREATE PROC <ProcedureName>ASBEGIN TRANBEGIN TRY<SPROC TEXT GOES HERE>COMMITEND TRYBEGIN CATCH-- check transaction stateIF XACT_STATE() = -1BEGINDECLARE @message xml-- get our deadlock info FROM the VIEWSET @message = '<TransactionLocks>' + (SELECT * FROM vLocks ORDER BY SPID FOR XML PATH('TransactionLock')) + '</TransactionLocks>'-- issue ROLLBACK so we don't ROLLBACK mail sendingROLLBACK-- get our error message and numberDECLARE @ErrorNumber INT, @ErrorMessage NVARCHAR(2048)SELECT @ErrorNumber = ERROR_NUMBER(), @ErrorMessage = ERROR_MESSAGE()-- if it's deadlock error send mail notificationIF @ErrorNumber = 1205BEGINDECLARE @MailBody NVARCHAR(max)-- create out mail body in the xml format. you can change this to your liking.SELECT @MailBody = '<DeadlockNotification>'+(SELECT 'Error number: ' + isnull(CAST(@ErrorNumber AS VARCHAR(5)), '-1') + CHAR(10) +'Error message: ' + isnull(@ErrorMessage, ' NO error message') + CHAR(10)FOR XML PATH('ErrorMeassage'))+CAST(ISNULL(@message, '') AS NVARCHAR(MAX))+'</DeadlockNotification>'-- for testing purposes-- SELECT CAST(@MailBody AS XML)-- send an email with the defined email profile.-- since this is async it doesn't halt executionEXEC msdb.dbo.sp_send_dbmail@profile_name = 'your mail profile',@recipients = 'dba@yourCompany.com',@subject = 'Deadlock occured notification',@body = @MailBody;ENDENDEND CATCHGOThe main part of this stored procedure is of course the CATCH block. The first line in there is check of the XACT_STATE()value. This is a scalar function that reports the user transactionstate. -1 means that the transaction is uncommittable and has to berolled back. This is the state of the victim transaction in theinternal deadlock killing process. Next we read from our vLocks view toget the full info (SPID, both SQL statements text, values, etc...)about both SPIDs that created a deadlock. This is possible since ourdeadlock victim transaction hasn't been rolled back yet and the locksare still present. We save this data into an XML message. Next werollback our transaction to release locks. With error message and it'scorresponding number we check if the error is 1205 - deadlock and if itis we send our message in an email. How to configure database mail canbe seen here.Both the view and the stored procedures template can and probably should be customized to suit your needs.Testing the theoryLet's try it out and see how it works with a textbook deadlock example that you can find in every book or tutorial.-- create our deadlock table with 2 simple rowsCREATE TABLE DeadlockTest ( id INT)INSERT INTO DeadlockTestSELECT 1 UNION ALLSELECT 2GONext create two stored procedures (spProc1 and spProc2) with our template:For spProc1 replace <SPROC TEXT GOES HERE> in the template with:UPDATE DeadlockTestSET id = 12WHERE id = 2-- wait 5 secs TO SET up deadlock condition IN other windowWAITFOR DELAY '00:00:05'UPDATE DeadlockTestSET id = 11WHERE id = 1For spProc2 replace <SPROC TEXT GOES HERE> in the template with:UPDATE DeadlockTestSET id = 11WHERE id = 1-- wait 5 secs TO SET up deadlock condition IN other windowWAITFOR DELAY '00:00:05'UPDATE DeadlockTestSET id = 12WHERE id = 2Next open 2 query windows in SSMS:In window 1 run put this script:exec spProc1In window 2 put this script:exec spProc2Run the script in the first window and after a second or two runthe script in the second window. A deadlock will happen and a fewmoments after the victim transaction fails you should get thenotification mail. Mail profile has to be properly configured ofcourse.The resulting email should contain an XML with full info about thedeadlock. You can view it by commenting msdb.dbo.sp_send_dbmailexecution and uncommenting the SELECT CAST(@MailBody AS XML) line.

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐