Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1372 Part IX Performance Tuning and Optimization Result: Spid Object Type Mode Status 54 HumanResources.Department PAGE IX GRANT 54 HumanResources.Department KEY X GRANT Transaction 2 ensures that the transaction isolation level is set to the default and then attempts to read the same row transaction 1 is updating: Transaction 2 USE AdventureWorks2008; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT Name FROM HumanResources.Department WHERE DepartmentID = 1; There is no result yet for transaction 2. It’s waiting for transaction 1 to complete — blocked by transac- tion 1’s exclusive lock. Requerying sys.dm_tran_locks reveals that the second transaction (SPID 51) has an intent to share (IS) read lock and is waiting for a share (S) read lock. Result: Spid Object Type Mode Status 51 HumanResources.Department PAGE IS GRANT 51 HumanResources.Department PAGE S WAIT 54 HumanResources.Department KEY X GRANT 54 HumanResources.Department PAGE IX GRANT 54 HumanResources.Department PAGE IX GRANT 54 HumanResources.Department KEY X GRANT 54 HumanResources.Department KEY X GRANT While transaction 1 is holding its exclusive lock, transaction 2 has to wait. In other words, transaction 1 is blocking transaction 2. Now, transaction 1 commits the transaction and releases the exclusive lock: Transaction 1 COMMIT TRANSACTION Immediately, transaction 1 completes and releases its locks. Transaction 2 springs to life and performs the select, reading the committed change. 1372 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1373 Managing Transactions, Locking, and Blocking 66 Result: Name New Name The point of transaction isolation level read committed is to avoid reading uncommitted data. What if the update doesn’t change the data? If transaction 1 updates the data from ‘‘John’’ to ‘‘John,’’ what’s the harm of reading ‘‘John’’? SQL Server handles this situation by not respecting an exclusive lock if the page hasn’t been changed, i.e., if the page isn’t flagged as dirty. This means that sometimes (because there’s probably more data on the page than just the data in question) SQL Server can avoid locking and blocking if the data isn’t actually being changed. Cool, no? You can prove this behavior by reexecuting the previous locking and blocking sample code with the same update value. Monitoring Locking and Blocking Without the ability to see the lock, the various types of locks and their durations may seem like pure theory. Fortunately, SQL Server is a relatively open environment, and it’s easy to inspect the current locks from several possible points of view. Viewing blocking with Management Studio reports With Management Studio, transaction information for a server or database may be seen using the Stan- dard Reports, available from the server or database context menus, which pull data from the dynamic management views. The transaction-related reports include All Transactions, All Blocking Transactions (shown in Figure 66-2), Top Transactions by Age, Top Transactions by Blocked Transaction Count, Top Transactions by Lock Count, Resource Locking by Object, and User Statistics. Viewing blocking with Activity Monitor The Activity Monitor (see Figure 66-3) is completely rewritten for SQL Server 2008 and includes process information. It’s available both on the toolbar and in the Object Explorer’s server context menu. For more information on the Activity Monitor, refer to Chapter 6, ‘‘Using Management Studio.’’ Using Profiler You can also use SQL Server Profiler to watch blocked processes using the Error and Warnings: Blocked Process Report event. 1373 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1374 Part IX Performance Tuning and Optimization FIGURE 66-2 Management Studio’s All Blocking Transactions Report is a quick way to view key transaction locking and blocking information. Best Practice O f the many possible methods to monitor locking and blocking, Activity Monitor and Management Studio’s Summary page provide the best overall view to determine whether locking and blocking is a problem. To home in on the specific locking and blocking issues, Profiler provides the actual code for the transactions involved. The catch to using Profiler is that by default the server is not configured to fire the blocked process event. To enable it, you have to configure the blocked process threshold setting. Because that’s an advanced option, you must enable ‘‘Show advanced options’’ first. The f ollowing snippet sets the blocking duration to one second: sp_configure ‘show advanced options’, 1; 1374 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1375 Managing Transactions, Locking, and Blocking 66 FIGURE 66-3 Activity Monitor displays information about the current locks and any blocking going on. In this instance, SPID 53 is blocking SPID 54. GO RECONFIGURE; GO sp_configure ‘blocked process threshold’, 1; GO RECONFIGURE; This means that the server will check every second for blocked statements, and for any statement that has been blocked for longer than one second, the blocked process report event will fire. Depending on when the last check was done, a statement may be blocked for more than the threshold value before it is reported. This can be seen by setting the threshold to a large value, say 10 seconds. The result is a complete XML-formatted disclosur e of the blocked and blocking process (see Fig- ure 66-4). Saving this trace to a file and analyzing it in total is an excellent locking and blocking debugging technique. 1375 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1376 Part IX Performance Tuning and Optimization FIGURE 66-4 SQL Server Profiler can monitor and display the blocked and blocking code in XML. Querying locks with DMVs Personally, I’m a big fan of SQL Server dynamic management views, but then I like to write queries. The sys.dm_exec_requests DMV reports several interesting facts about current sessions, including the blocking session ID: SELECT session_id, blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id > 0 My friend and SQL Server MVP Adam Machanic has developed an extensive script based on this DMV that reports all active sessions, their statements, and their blocking status. It’s available at: http://sqlblog.com/blogs/adam machanic/archive/2008/12/31/a-gift-of-script- for-2009-who-is-active-redux.aspx . Viewing all the locks is possible with the sys.dn_tran_locks DMV. The following query joins with other DMVs to provide a complete picture of the locks in a database: 1376 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1377 Managing Transactions, Locking, and Blocking 66 SELECT request_session_id as Spid, Coalesce(s.name + ‘.’ + o.name + isnull(‘.’ + i.name,’’), s2.name + ‘.’ + o2.name, db.name) AS Object, l.resource_type as Type, request_mode as Mode, request_status as Status FROM sys.dm_tran_locks l LEFT JOIN sys.partitions p ON l.resource_associated_entity_id = p.hobt_id LEFT JOIN sys.indexes i ON p.object_id = i.object_id AND p.index_id = i.index_id LEFT JOIN sys.objects o ON p.object_id = o.object_id LEFT JOIN sys.schemas s ON o.schema_id = s.schema_id LEFT JOIN sys.objects o2 ON l.resource_associated_entity_id = o2.object_id LEFT JOIN sys.schemas s2 ON o2.schema_id = s2.schema_id LEFT JOIN sys.databases db ON l.resource_database_id = db.database_id WHERE resource_database_id = DB_ID() ORDER BY Spid, Object, CASE l.resource_type When ‘database’ Then 1 when ‘object’ then 2 when ‘page’ then 3 when ‘key’ then 4 Else 5 end Deadlocks A deadlock is a special situation that occurs only when transactions with multiple tasks compete for the same data resource out of order. For example: ■ Transaction 1 has a lock on data A and needs to lock data B to complete its transaction. and ■ Transaction 2 has a lock on data B and needs to lock data A to complete its transaction. Each transaction is stuck waiting for the other to release its lock, and neither can complete until the other does. Unless an outside force intercedes, or one of the transactions gives up and quits, this situation could last until the end of time. 1377 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1378 Part IX Performance Tuning and Optimization While a deadlock typically involves two transactions, it can be a cyclic locking and blocking problem involving several transactions — for example, A i s waiting on B, which is waiting on C, which is waiting on A. Deadlocks used to be a serious problem. Fortunately, SQL Server handles deadlocks refreshingly well. I’ve seen deadlocks result from a single parallelized UPDATE query. The parallel threads of the query deadlocked on index updates. This is why I strongly recommend that OLTP servers run with maximum degree of parallelism (maxdop) set to 1. Creating a deadlock It’s easy to create a deadlock situation in SQL Server using two connections in Management Studio’s Query Editor, as illustrated in Figure 66-5. Transaction 1 and transaction 2 will simply try to update the same rows but in the opposite order. Use a third window to watch the locks using Activity Monitor or one of the DMV queries. FIGURE 66-5 Creating a deadlock situation in Management Studio using two connections tiled vertically 1378 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1379 Managing Transactions, Locking, and Blocking 66 To execute the code, you’ll need to do the following: 1. Create two query windows. In one paste the following: Transaction 1 Step 1 USE OBXKites BEGIN TRANSACTION Update Contact SET LastName = ‘Jorgenson’ WHERE ContactCode = ‘101’ Transaction 1 Step 3 Update Product SET ProductName = ‘DeadLock Identification Tester’ Where ProductCode = ‘1001’ COMMIT TRANSACTION 2. Paste the following in the second window: Transaction 2 Step 2 USE OBXKites BEGIN TRANSACTION Update Product SET ProductName = ‘DeadLock Repair Kit’ Where ProductCode = ‘1001’ Update Contact SET FirstName = ‘Neals’ Where ContactCode = ‘101’ COMMIT TRANSACTION Execute in the code in the first query window: Transaction 1 Step 1 USE OBXKites BEGIN TRANSACTION Update Contact SET LastName = ‘Jorgenson’ WHERE ContactCode = ‘101’ Transaction 1 now has an exclusive lock on ContactCode 101. Execute step 2 in the second window: 1379 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1380 Part IX Performance Tuning and Optimization Transaction 2 Step 2 USE OBXKites BEGIN TRANSACTION Update Product SET ProductName = ‘DeadLock Repair Kit’ Where ProductCode = ‘1001’ Update Contact SET FirstName = ‘Neals’ Where ContactCode = ‘101’ COMMIT TRANSACTION Transaction 2 will gain an exclusive lock on ProductCode 1001 and then try to grab an exclusive lock on ContactCode 101, but transaction 1 already has it locked. It’s not a deadlock yet because although transaction 2 is waiting for transaction 1, transaction 1 is not waiting for transaction 2. At this point, if transaction 1 finished its work and issued a COMMIT TRANSACTION , the data resource would be freed; transaction 2 could get its lock on the contact row and be on its way as well. The trouble begins when transaction 1 tries to update ProductCode 1001. It can’t get an exclusive lock because transaction 2 already has an exclusive lock. So when the following code is executed: Transaction 1 Step 3 Update Product SET ProductName = ‘DeadLock Identification Tester’ Where ProductCode = ‘1001’ COMMIT TRANSACTION transaction one returns the following friendly error message in about two seconds. The deadlock can also be viewed using SQL Server Profiler (as shown in Figure 66-6). Server: Msg 1205, Level 13, State 50, Line 1 Transaction (Process ID 5173) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. Transaction 2 completes as if there’s no problem. Result: (1 row(s) affected) (1 row(s) affected) 1380 www.getcoolebook.com Nielsen c66.tex V4 - 07/21/2009 4:13pm Page 1381 Managing Transactions, Locking, and Blocking 66 FIGURE 66-6 SQL Server Profiler can monitor deadlocks using the Locks: Deadlock Graph event and can display the resource conflict that caused the deadlock. Automatic deadlock detection As the previous deadlock code demonstrated, SQL Server automatically detects a deadlock situation by examining the blocking processes and rolling back the transaction that has performed the least amount of work. A process within SQL Server is constantly checking for cross-blocking locks and even detects deadlocks that span multiple servers using distributed queries. The deadlock-detection delay is typically instantaneous. Handling deadlocks Once a deadlock occurs, SQL Server will determine the transaction to roll back based on an estimate of the amount of work it requires. The transaction selected as the deadlock victim will need to be performed again. Before SQL Server 2005, trapping a deadlock could only occur at the client, but fortunately try-catch error-handling code can trap a 1205 error, and deadlocks can now be handled in the catch block. If you catch the deadlock within the transaction, your only option is to roll back the transaction. However, you can then rerun your transaction using T-SQL logic, as shown in the following example: 1381 www.getcoolebook.com . HumanResources.Department PAGE IS GRANT 51 HumanResources.Department PAGE S WAIT 54 HumanResources.Department KEY X GRANT 54 HumanResources.Department PAGE IX GRANT 54 HumanResources.Department PAGE. Figure 66-3) is completely rewritten for SQL Server 2008 and includes process information. It’s available both on the toolbar and in the Object Explorer’s server context menu. For more information. demonstrated, SQL Server automatically detects a deadlock situation by examining the blocking processes and rolling back the transaction that has performed the least amount of work. A process within SQL Server