Lock Escalation When SQL Server detects that the locks acquired by a query are using too much memory and consuming too many system resources for the Lock Manager to manage the locks effi
Trang 1CHAPTER 37 Locking and Performance
could lead to greater page-level contention because the likelihood of the data rows being
requested by different processes residing on the same page is greater Using row-level
locking increases the concurrent access to the data
On the other hand, row-level locking consumes more resources (memory and CPU) than
page-level locks simply because there is a greater number of rows than pages in a table If
a process needed to access all rows on a page, it would be more efficient to lock the entire
page than acquire a lock for each individual row This would result in a reduction in the
number of lock structures in memory that the Lock Manager would have to manage
Which is better—greater concurrency or lower overhead? As shown earlier, in Figure 37.6,
it’s a trade-off As lock size decreases, concurrency improves, but performance degrades
due to the extra overhead As the lock size increases, performance improves due to less
overhead, but concurrency degrades Depending on the application, the database design,
and the data, either page-level or row-level locking can be shown to be better than the
other in different circumstances
SQL Server makes the determination automatically at runtime—based on the nature of the
query, the size of the table, and the estimated number of rows affected—of whether to
initially lock rows, pages, or the entire table In general, SQL Server attempts to first lock
at the row level more often than the page level, in an effort to provide the best
concur-rency With the speed of today’s CPUs and the large memory support, the overhead of
managing row locks is not as expensive as in the past However, as the query processes
and the actual number of resources locked exceed certain thresholds, SQL Server might
attempt to escalate locks from a lower level to a higher level, as appropriate
At times, SQL Server might choose to do both row and page locking for the same query For
example, if a query returns multiple rows, and if enough contiguous keys in a nonclustered
index page are selected to satisfy the query, SQL Server might place page locks on the index
while using row locks on the data This reduces the need for lock escalation
Lock Escalation
When SQL Server detects that the locks acquired by a query are using too much memory
and consuming too many system resources for the Lock Manager to manage the locks
effi-ciently, it automatically attempts to escalate row, key, or page locks to table-level locks
For example, because a query on a table continues to acquire row locks and every row in
the table will eventually be accessed, it makes sense for SQL Server to escalate the row
locks to a table-level lock After the table-level lock is acquired, the row-level locks are
released This helps reduce locking overhead and keeps the system from running out of
available lock structures Recall from earlier sections in this chapter that the potential
need for lock escalation is reflected in the intent locks that are acquired on the table by
the process locking at the row or page level While the default behavior in SQL Server is to
escalate to table-level locks, SQL Server 2008 introduces the capability to escalate row or
page locks to a single partition via theLOCK_ESCALATIONsetting inALTER TABLE This new
option allows you to specify whether escalation is always to the table or partition level
TheLOCK_ESCALATIONsetting can also be used to prevent lock escalation entirely
Trang 2NOTE
SQL Server never escalates row locks to page locks, only to table or partition-level
locks Also, multiple partition-level locks are never escalated to a single table-level
lock
What are the lock escalation thresholds in SQL Server? Currently, SQL Server attempts
lock escalation under the following conditions:
Whenever a single T-SQL statement acquires at least 5,000 locks on a single reference
of a table, table partition, or index (this value is subject to change in subsequent
service packs) Note that lock escalation does not occur if the locks are spread across
multiple objects in the same statement—for example, 4,000 locks on one index and
2,500 locks on another
When the amount of memory required by lock resources exceeds 40% of the
avail-able Database Engine memory pool
NOTE
Generally, if more memory is required for lock resources than is currently available in
the Database Engine memory pool, the Database Engine allocates additional memory
dynamically to satisfy the request for locks as long as more computer memory is
avail-able and the max server memorythreshold has not been reached However, if
allocat-ing additional memory would cause pagallocat-ing at the operatallocat-ing system level, more lock
space is not allocated If no more memory is available, or the amount of memory
allo-cated to lock resources reaches 60% of the memory acquired by an instance of the
Database Engine, further requests for locks generate an out-of-lock memory error
If locks cannot be escalated because of lock conflicts, SQL Server reattempts lock escalation
when every 1,250 additional locks are acquired For example, if another process is also
holding locks at the page or row level on the same table (indicated by the presence of that
process’s intent lock on the table), lock escalation cannot take place if the lock types are
not compatible until the lower-level locks are released by the other processes In this case,
SQL Server continues acquiring locks at the row or page level until the table lock becomes
available
Controlling Lock Escalation
Escalating locks to the table or partition level can lead to locking contention or blocking
for other transactions attempting to access a row or page in the same table Under certain
circumstances, you might want to disable lock escalation
As mentioned previously, lock escalation can be enabled or disabled at the table level
using the ALTER TABLEcommand:
ALTER TABLE tablename set (LOCK_ESCALATION ={ AUTO | TABLE | DISABLE } )
Trang 3CHAPTER 37 Locking and Performance
Setting the option to AUTOallows SQL Server to escalate to the table or partition level
Setting the option to DISABLEprevents escalation to the table or partition level
SQL Server 2008 also supports disabling lock escalation for all tables in all databases
within a SQL Server instance using either the 1211 or 1224 trace flags Trace flag 1211
completely disables lock escalation, regardless of the memory required for lock resources
However, when the amount of memory required for lock resources exceeds 60% of the
maximum available Database Engine memory, an out-of-lock memory error is generated
Alternatively, trace flag 1224 disables the built-in lock escalation based on the number of
locks acquired, but lock escalation is still possible when the 40% of available Database
Engine memory threshold is reached However, as noted previously, if the locks cannot be
escalated, SQL Server could still run out of available memory for locks
NOTE
You should be extremely careful when considering disabling lock escalation via the
trace flags A poorly designed application could potentially exhaust the available SQL
Server memory with excessive lock structures and seriously degrade SQL Server
perfor-mance It is usually preferable to control lock escalation at the object level via the
ALTER TABLEcommand
Lock Compatibility
If a process has already locked a resource, the granting of lock requests by other
transac-tions on the same resource is governed by the lock compatibility matrix within SQL
Server Table 37.3 shows the lock compatibility matrix for the locks most commonly
acquired by the SQL Server Lock Manager, indicating which lock types are compatible and
which lock types are incompatible when requested on the same resource
TABLE 37.3 SQL Server Lock Compatibility Matrix
Requested Lock Type Existing Lock Type
Intent shared Yes Yes Yes Yes Yes No Yes No No
Intent exclusive Yes No No Yes No No Yes No No
Shared with intent exclusive Yes No No No No No Yes No No
Schema stability Yes Yes Yes Yes Yes Yes Yes No Yes
Trang 4For example, if a transaction has acquired a shared lock on a resource, the possible lock
types that can be acquired on the resource by other transactions are intent shared, shared,
update, and schema stability locks Intent exclusive, SIX, exclusive, schema modification,
and bulk update locks are incompatible with a shared lock and cannot be acquired on the
resource until the shared lock is released
Locking Contention and Deadlocks
In the grand scheme of things, the most likely culprits of SQL Server application
perfor-mance problems are typically poorly written queries, poor database and index design, and
locking contention Whereas the first two problems result in poor application
perfor-mance, regardless of the number of users on the system, locking contention becomes
more of a performance problem as the number of users increases It is further
compounded by increasingly complex or long-running transactions
Locking contention occurs when a transaction requests a lock type on a resource that is
incompatible with an existing lock type on the resource By default, the process waits
indefinitely for the lock resource to become available Locking contention is noticed in
the client application through the apparent lack of response from SQL Server
Figure 37.9 demonstrates an example of locking contention Process 1 has initiated a
transaction and acquired an exclusive lock on page 1:325 Before Process 1 can acquire the
lock that it needs on page 1:341 to complete its transaction, Process 2 acquires an
exclu-sive lock on page 1:341 Until Process 2 commits or rolls back its transaction and releases
the lock on Page 1:341, the lock continues to be held Because this is not a deadlock
scenario (which is covered in the “Deadlocks” section, later in this chapter), by default,
SQL Server takes no action Process 1 simply waits indefinitely
Page 1:325
Page 1:341
Locks
1
2 3
X
X
Lock Wait
X
FIGURE 37.9 Locking contention between two processes
Trang 5CHAPTER 37 Locking and Performance
Identifying Locking Contention
When a client application appears to freeze after submitting a query, this is often due to
locking contention To identify locking contention between processes, you can use the
SSMS Activity Monitor, as discussed earlier in this chapter, in the “Monitoring Lock
Activity in SQL Server” section; use the sp_who2stored procedure; or query the
sys.dm_tran_lockssystem catalog view Figure 37.10 shows an example of a blocking lock
as viewed in the SSMS Activity Monitor
To identify whether a process is being blocked using sp_who2, examine the BlkBycolumn
If any value besides ‘-’ is displayed, it is the SPID of the process that is holding the
block-ing lock In the followblock-ing output of sp_who2(edited for space), you can see that process 57
isSUSPENDED, waiting on a lock held by process 53:
exec sp_who2
go
SPID Status Login HostName BlkBy DBName Command
- - - - - -
-*** info for internal processes deleted -***
51 sleeping rrankins LATITUDED830-W7 master AWAITING COMMAND
52 sleeping SQLADMIN LATITUDED830-W7 msdb AWAITING COMMAND
53 sleeping rrankins LATITUDED830-W7 bigpubs2008 AWAITING COMMAND
54 sleeping rrankins LATITUDED830-W7 tempdb AWAITING COMMAND
FIGURE 37.10 Examining locking contention between two processes in SSMS Activity Monitor
Trang 655 sleeping rrankins LATITUDED830-W7 master AWAITING COMMAND
56 sleeping SQLADMIN LATITUDED830-W7 msdb AWAITING COMMAND
57 SUSPENDED rrankins LATITUDED830-W7 53 bigpubs2008 INSERT
58 sleeping rrankins LATITUDED830-W7 bigpubs2008 AWAITING COMMAND
59 RUNNABLE rrankins LATITUDED830-W7 master SELECT INTO
To determine what table, page, or rows are involved in blocking and at what level the
blocking is occurring, you can query the sys.dm_tran_lockscatalog view, as shown in
Listing 37.5
LISTING 37.5 Viewing Locking Contention by Using the sys.dm_tran_locks View
use bigpubs2008
go
select str(request_session_id, 4,0) as spid,
convert (varchar(12), db_name(resource_database_id)) As db_name,
case when resource_database_id = db_id() and resource_type = ‘OBJECT’
then convert(char(12), object_name(resource_Associated_Entity_id))
else convert(char(16), resource_Associated_Entity_id)
end as object,
convert(varchar(12), resource_type) as resource_type,
convert(varchar(8), request_mode) as mode,
convert(varchar(14), resource_description) as resource_desc,
convert(varchar(6), request_status) as status
from sys.dm_tran_locks
order by request_session_id, 3 desc
go
spid db_name object resource_type mode resource_desc status
-
-52 msdb 0 DATABASE S GRANT
53 bigpubs2008 673416192655360 PAGE IX 1:608 GRANT
53 bigpubs2008 673416192655360 KEY X (928195c101b1) GRANT
53 bigpubs2008 391941215944704 KEY X (59d1a826552c) GRANT
53 bigpubs2008 391941215944704 PAGE IX 1:280 GRANT
53 bigpubs2008 stores OBJECT IX GRANT
53 bigpubs2008 0 DATABASE S GRANT
56 msdb 0 DATABASE S GRANT
57 bigpubs2008 391941215944704 PAGE IS 1:280 GRANT
57 bigpubs2008 391941215944704 KEY S (59d1a826552c) WAIT
57 bigpubs2008 stores OBJECT IS GRANT
57 bigpubs2008 0 DATABASE S GRANT
From this output, you can see that Process 57 is waiting for a shared (S) lock on key
59d1a826552cof page 1:280 of the storestable Process 53 has an intent exclusive (IX)
Trang 7CHAPTER 37 Locking and Performance
lock on that page because it has an exclusive (X) lock on a key on that page (Both have
the same resource_Associated_Entity_idof59d1a826552c.)
As an alternative to sp_whoand the sys.dm_tran_locksview, you can also get specific
information on any blocked processes by querying the sys.dm_os_waiting_taskssystem
catalog view, as shown in Listing 37.6
LISTING 37.6 Viewing Blocked Processes by Using the sys.dm_os_waiting_tasks View
select convert(char(4), session_id) as spid,
convert(char(8), wait_duration_ms) as duration,
convert(char(8), wait_type) as wait_type,
convert(char(3), blocking_session_id) as blk,
resource_description
from sys.dm_os_waiting_tasks
where blocking_session_id is not null
go
spid duration wait_type blk resource_description
- -
-
-57 134118 LCK_M_S 53 keylock hobtid=391941215944704 dbid=8 id=lockfd43800
mode=X associatedObjectId=391941215944704
Setting the Lock Timeout Interval
If you do not want a process to wait indefinitely for a lock to become available, SQL Server
allows you to set a lock timeout interval by using the SET LOCK_TIMEOUTcommand You
specify the timeout interval in milliseconds For example, if you want your processes to
wait only 5 seconds (that is, 5,000 milliseconds) for a lock to become available, you
execute the following command in the session:
SET LOCK_TIMEOUT 5000
If your process requests a lock resource that cannot be granted within 5 seconds, the
state-ment is aborted, and you get the following error message:
Server: Msg 1222, Level 16, State 52, Line 1
Lock request time out period exceeded
To examine the current LOCK_TIMEOUTsetting, you can query the system function
@@lock_timeout:
select @@lock_timeout
go
-5000
Trang 8If you want processes to abort immediately if the lock cannot be granted (in other words,
no waiting at all), you set the timeout interval to 0 If you want to set the timeout interval
back to infinity, execute the SET_LOCK_TIMEOUTcommand and specify a timeout interval
of-1
Minimizing Locking Contention
Although setting the lock timeout prevents a process from waiting indefinitely for a lock
request to be granted, it doesn’t address the cause of the locking contention In an effort
to maximize concurrency and application performance, you should minimize locking
contention between processes as much as possible Some general guidelines to follow to
minimize locking contention include the following:
Keep transactions as short and concise as possible The shorter the period of time
locks are held, the less chance for lock contention Keep commands that are not
essential to the unit of work being managed by the transaction (for example,
assign-ment selects, retrieval of updated or inserted rows) outside the transaction
Keep statements that comprise a transaction in a single batch to eliminate
unneces-sary delays caused by network input/output (I/O) between the initial BEGIN TRAN
statement and the subsequent COMMIT TRANcommands
Consider coding transactions entirely within stored procedures Stored procedures
typically run faster than commands executed from a batch In addition, because
they are server resident, stored procedures reduce the amount of network I/O that
occurs during execution of the transaction, resulting in faster completion of the
transaction
Commit updates in cursors frequently and as soon as possible Cursor processing is
much slower than set-oriented processing and causes locks to be held longer
NOTE
Even though cursors might run more slowly than set-oriented processing, cursors can
sometimes be used to minimize locking contention for updates and deletions of a large
number of rows from a table, which might result in a table lock being acquired The
UPDATEorDELETEstatement itself might complete faster; however, if it is running with
an exclusive lock on the table, then no other process can access the table until it
pletes By using a cursor to update a large number of rows one row at a time and
com-mitting the changes frequently, the cursor uses page- or row-level locks rather than a
table-level lock It might take longer for the cursor to complete the actual update or
delete, but while the cursor is running, other processes are still able to access other
rows or pages in the table that the cursor doesn’t currently have locked
Use the lowest level of locking isolation required by each process For example, if
dirty reads are acceptable and accurate results are not imperative, consider using
transaction Isolation Level 0 Use the Repeatable Read or Serializable Read isolation
levels only if absolutely necessary
Trang 9CHAPTER 37 Locking and Performance
Never allow user interaction between a BEGIN TRANstatement and a COMMIT TRAN
statement because doing so may cause locks to be held for an indefinite period of
time If a process needs to return rows for user interaction and then update one or
more rows, consider using optimistic locking or Snapshot Isolation in your
applica-tion (Optimistic locking is covered in the “Optimistic Locking” section, later in this
chapter.)
Minimize “hot spots” in a table Hot spots occur when the majority of the update
activity on a table occurs within a small number of pages For example, hot spots
occur for concurrent insertions to the last page of a heap table or the last pages of a
table with a clustered index on a sequential key You can often eliminate hot spots
by creating a clustered index in a table on a column or columns to order the rows in
the table in such a way that insert and update activity is spread out more evenly
across the pages in the table
Deadlocks
A deadlock occurs when two processes are each waiting for a locked resource that the other
process currently holds Neither process can move forward until it receives the requested
lock on the resource, and neither process can release the lock it is currently holding until
it can receive the requested lock Essentially, neither process can move forward until the
other one completes, and neither one can complete until it can move forward
Two primary types of deadlocks can occur in SQL Server:
Cycle deadlocks—A cycle deadlock occurs when two processes acquire locks on
different resources, and then each needs to acquire a lock on the resource that the
other process has Figure 37.11 demonstrates an example of a cycle deadlock
In Figure 37.11, Process 1 acquires an exclusive lock on page 1:201 in a transaction
At the same time, Process 2 acquires an exclusive lock on page 1:301 in a
Page 1:201
Page 1:301
Locks
Requests
Requests
Locks
1
2
4
3
Lock Wait
X
Lock Wait
X
FIGURE 37.11 An example of a cycle deadlock
Trang 10tion Process 1 then attempts to acquire a lock on page 1:301 and begins waiting for
the lock to become available Simultaneously, Process 2 requests an exclusive lock on
page 1:201, and a deadlock, or “deadly embrace,” occurs
Conversion deadlocks—A conversion deadlock occurs when two or more processes
each hold a shared lock on the same resource within a transaction and each wants
to promote the shared lock to an exclusive lock, but neither can do so until the
other releases the shared lock An example of a conversion deadlock is shown in
Figure 37.12
It is often assumed that deadlocks happen at the data page or data row level In fact,
dead-locks often occur at the index page or index key level Figure 37.13 depicts a scenario in
which a deadlock occurs due to contention at the index key level
SQL Server automatically detects when a deadlock situation occurs A separate process in
SQL Server, called LOCK_MONITOR, checks the system for deadlocks roughly every 5 seconds
In the first pass, this process detects all the processes that are waiting on a lock resource
TheLOCK_MONITORthread checks for deadlocks by examining the list of waiting lock
requests to see if any circular lock requests exist between the processes holding locks and
the processes waiting for locks When the LOCK_MONITORdetects a deadlock, SQL Server
aborts the transaction of one of the involved processes How does SQL Server determine
which process to abort? It attempts to choose as the deadlock victim the transaction that
it estimates would be least expensive to roll back If both processes involved in the
dead-lock have the same rollback cost and the same deaddead-lock priority, the deaddead-lock victim is
chosen randomly
Page 1:201
Locks
Requests
Locks
Locks
1
4
2
3
Lock Wait X X
FIGURE 37.12 An example of a conversion deadlock