Pages

Monday 5 March 2018

Lock Types

Lock Types:
Microsoft SQL Server 2000 has multigranular locking that allows different types of resources to be locked by a transaction. To minimize the cost of locking,SQL Server locks resources automatically at a level appropriate to the task. Locking at a smaller granularity, such as rows, increases concurrency, but has a higher overhead because more locks must be held if many rows are locked. Locking at a larger granularity, such as tables, are expensive in terms of concurrency because locking an entire table restricts access to any part of the table by other transactions, but has a lower overhead because fewer locks are being maintained.

SQL Server can lock these resources (listed in order of increasing granularity).

Resource
Description
RID
Row identifier. Used to lock a single row within a table.
Key
Row lock within an index. Used to protect key ranges in serializable transactions.
Page
8 kilobyte –(KB) data page or index page.
Extent
Contiguous group of eight data pages or index pages.
Table
Entire table, including all data and indexes.
DB
Database.

In addition to tables, pages, rows and keys, the following listing provides information on the other common types of resources that are targets for locks. These will crop up from time to time in your queries against sys.dm_tran_locks.

Key ranges only occur under the SERIALIZABLE isolation level where protection against phantom reads requires locking of a range of values to ensure that no one can insert records into a range that is scanned.

Extents – locked when tables and indexes grow, and extents are added as a result.

Databases – processes will be issued a shared (S) lock against a database if it locks a resource within a database. This occurs in any database on a SQL instance with the exception of master and tempdb, which allows the SQL engine to perform a check for locks prior to dropping a database or taking it offline, for instance. You will see a DATABASE lock for each request. I filter out DATABASE locks in my locking / blocking queries and consider them noise results.

Allocation units – locked when they are in the process of being de-allocated.

Metadata – occur when a transaction is attempting to change the definition for a given object. For example, altering the recovery model on a database would register an exclusive lock on the Metadata object type for the affected database.

The resource targeted by a given lock is exposed by the resource_type column in the sys.dm_tran_locks DMV.






So let’s start with the lock types. What is the lock? In short, this is in-memory structure (64 bytes on 32 bit OS or 128 bytes on 64 bit OS). The structure has the owner, type and resource hash that links it to the resource it protects (row, page, table, file, database, etc). Obviously it’s more complicated and has quite a few other attributes, but for our practical purposes that level of details is enough.

SQL Server has more than 20 different lock types but for now let’s focus on the most important ones.

Shared locks (S)
Shared locks are held on data being read under the pessimistic concurrency model. While a shared lock is being held other transactions can read but can't modify locked data.

Multiple shared locks can be issued for the same resource, hence the term "shared."

Usually, SQL Server releases S locks as soon as it has finished reading the data. However,use of a higher transaction isolation level, either REPEATABLE READ or SERIALIZABLE,changes this behavior, so that SQL Server holds S locks until the end of the transaction.

In the sys.dm_tran_locks view, a request_mode of 'S' indicates a shared lock.

In the example you can't see the shared locks because they're taken for the duration of the select statement and are already released when we would select data from sys.dm_tran_locks. That is why an addition of WITH (HOLDLOCK) is needed to see the locks.

BEGIN TRAN

USE AdventureWorks2008

SELECT * FROM Person.Address WITH (HOLDLOCK)
WHERE AddressId = 2

SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'

ROLLBACK






Update locks (U)

UPDATE locks are not really a separate kind of lock, but rather are a hybrid of SHARED and EXCLUSIVE locks. And contrary to what you might think, UPDATE locks are not just acquired for UPDATE operations.  A transaction acquires this kind of lock when SQL Server executes a data modification operation but first needs to perform a search to find the resource to modify.

While SQL Server is searching, it shouldn’t need to acquire an EXCLUSIVE lock; it only needs the EXCLUSIVE lock when the data to be changed is found. Normally, if a SQL Server process was just searching for data, it would acquire a SHARED lock on each resource it encounters and then determines whether it has found the data it is searching for. However, if SQL Server started out with a SHARED lock while searching for the data to modify, there are potential problems. A situation could occur where two processes were both searching for the same resource to modify (for example, the same customer row in the Customers table), using different access paths, and they could both reach the desired resource at the same time. If they both were acquiring SHARED locks on the data they were examining, they could both lock the resource they wanted to change, but before they made the modification they would have to convert their lock to an EXCLUSIVE lock. Since the other process would have a SHARED lock, no EXCLUSIVE lock could be granted. Each process would have a SHARED lock, and each would try to change it to an EXCLUSIVE lock, but neither could proceed because of the presence of the other. This is a deadlock situation, called a ‘conversion deadlock’. 

UPDATE locks are really a deadlock avoidance mechanism. If SQL Server uses UPDATE locks, a deadlock will NOT occur. If a SQL Server process begins a search operation with the intention of eventually modifying data, it acquires UPDATE locks until it finds the data to modify. UPDATE locks are compatible with SHARED locks, but are not compatible with EXCLUSIVE locks or other UPDATE locks. So if two processes were searching for the same data resource, the first one to reach it would acquire an UPDATE lock, and then the second process could not get any lock and would wait for the first process to be done. Since the first process was not blocked, it could convert its UPDATE lock to an EXCLUSIVE lock, make the data modification, and finish its transaction and release its locks. Then the second process could make its change.

In the sys.dm_tran_locks view, a request_mode of 'U' indicates an update lock.



Exclusive locks (X)

Exclusive (X) locks prevent access to a resource by concurrent transactions. With an exclusive (X) lock, no other transactions can modify data; read operations can take place only with the use of the NOLOCK hint or read uncommitted isolation level.

Data modification statements, such as INSERT, UPDATE, and DELETE combine both modification and read operations. The statement first performs read operations to acquire data before performing the required modification operations. Data modification statements, therefore, typically request both shared locks and exclusive locks.

In the sys.dm_tran_locks view, a request_mode of 'X' indicates an exclusive lock.

For example, an UPDATE statement might modify rows in one table based on a join with another table. In this case, the UPDATE statement requests shared locks on the rows read in the join table in addition to requesting exclusive locks on the updated rows.

BEGIN TRAN
USE AdventureWorks2008

UPDATE Person.Address
SET AddressLine2 = 'Test Address 2'
WHERE AddressId = 5

SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'

ROLLBACK





Intent locks (I)
The Database Engine uses intent locks to protect placing a shared (S) lock or exclusive (X) lock on a resource lower in the lock hierarchy. Intent locks are named intent locks because they are acquired before a lock at the lower level, and therefore signal intent to place locks at a lower level.
Intent locks serve two purposes:
·         To prevent other transactions from modifying the higher-level resource in a way that would invalidate the lock at the lower level.
·         To improve the efficiency of the Database Engine in detecting lock conflicts at the higher level of granularity.
For example, a shared intent lock is requested at the table level before shared (S) locks are requested on pages or rows within that table. Setting an intent lock at the table level prevents another transaction from subsequently acquiring an exclusive (X) lock on the table containing that page. Intent locks improve performance because the Database Engine examines intent locks only at the table level to determine if a transaction can safely acquire a lock on that table. This removes the requirement to examine every row or page lock on the table to determine if a transaction can lock the entire table.
Intent locks include intent shared (IS), intent exclusive (IX), and shared with intent exclusive (SIX).
Lock mode
Description
Intent shared (IS)
Protects requested or acquired shared locks on some (but not all) resources lower in the hierarchy.
Intent exclusive (IX)
Protects requested or acquired exclusive locks on some (but not all) resources lower in the hierarchy. IX is a superset of IS, and it also protects requesting shared locks on lower level resources.
Shared with intent exclusive (SIX)
Protects requested or acquired shared locks on all resources lower in the hierarchy and intent exclusive locks on some (but not all) of the lower level resources. Concurrent IS locks at the top-level resource are allowed. For example, acquiring a SIX lock on a table also acquires intent exclusive locks on the pages being modified and exclusive locks on the modified rows. There can be only one SIX lock per resource at one time, preventing updates to the resource made by other transactions, although other transactions can read resources lower in the hierarchy by obtaining IS locks at the table level.
Intent update (IU)
Protects requested or acquired update locks on all resources lower in the hierachy. IU locks are used only on page resources. IU locks are converted to IX locks if an update operation takes place.
Shared intent update (SIU)
A combination of S and IU locks, as a result of acquiring these locks separately and simultaneously holding both locks. For example, a transaction executes a query with the PAGLOCK hint and then executes an update operation. The query with the PAGLOCK hint acquires the S lock, and the update operation acquires the IU lock.
Update intent exclusive (UIX)
A combination of U and IX locks, as a result of acquiring these locks separately and simultaneously holding both locks.

The request_mode column of the sys.dm_tran_locks view by IS, IX and IU, respectively.

BEGIN TRAN
USE AdventureWorks2008

UPDATE TOP (5) Person.Address
SET AddressLine2 = 'Test Address 2'
WHERE AddressId = 5

SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'

ROLLBACK




Schema locks (Sch)

There are two types of schema locks:

Schema stability lock (Sch-S): Used while generating execution plans. These locks don't block access to the object data.

Schema modification lock (Sch-M): Used while executing a DDL statement. Blocks access to the object data since its structure is being changed.
In the example we can see the Sch-S and Sch-M locks being taken on the system tables and the TestTable plus a lot of other locks on the system tables.

BEGIN TRAN
USE AdventureWorks2008

CREATE TABLE TestTable (TestColumn INT)

SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'

ROLLBACK




Bulk Update locks (BU)

Bulk Update locks are used by bulk operations when TABLOCK hint is used by the import. This allows for multiple fast concurrent inserts by disallowing data reading to other transactions.

Conversion locks:

Conversion locks are locks resulting from converting one type of lock to another. There are 3 types of conversion locks:

Shared with Intent Exclusive (SIX). A transaction that holds a Shared lock also has some pages/rows locked with an Exclusive lock

Shared with Intent Update (SIU). A transaction that holds a Shared lock also has some pages/rows locked with an Update lock.

Update with Intent Exclusive (UIX). A transaction that holds an Update lock also has some pages/rows locked with an Exclusive lock.

In the example you can see the UIX conversion lock being taken on the page:

BEGIN TRAN
USE AdventureWorks2008

UPDATE TOP(5) Person.Address
SET AddressLine2 = 'Test Address 2'
WHERE PostalCode = '98011'

SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'

ROLLBACK




Key - Range locks:

Key-range locks protect a range of rows implicitly included in a record set being read by a Transact-SQL statement while using the serializable transaction isolation level. Key-range locking prevents phantom reads. By protecting the ranges of keys between rows, it also prevents phantom insertions or deletions into a record set accessed by a transaction. In the example we can see that there are two types of key-range locks taken:

RangeX-X - exclusive lock on the interval between the keys and exclusive lock on the last key in the range

RangeS-U – shared lock on the interval between the keys and update lock on the last key in the range

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRAN
USE AdventureWorks2008

UPDATE Person.Address
SET AddressLine2 = 'Test Address 2'
WHERE AddressLine1 LIKE '987 %'

SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'

ROLLBACK



Lock duration:

The length of time that SQL Server holds a lock depends primarily on the mode of the lock and the transaction isolation level that is in effect.

Read Uncommited won’t holds Shared Locks

READ COMMITTED is SQL Server's default isolation level.
At this level, SQL Server releases S locks as soon as it has read and processed the locked data.
It holds an X lock until the end of the transaction, whether the transaction is committed or rolled back.
It holds a U lock until the end of the transaction,unless it promoted the U lock to an X lock, in which case the X lock, as with all X locks,
remains for the duration of the transaction.


If the transaction isolation level is REPEATABLE READ or SERIALIZABLE, S locks have the same duration as X locks. That is, SQL Server does not release them until the transaction is over.

In addition to changing the transaction isolation level, we can control the lock duration by using lock hints.





Lock ownership:
We can think of lock ownership as the scope of the lock, and it can affect lock duration. There are three default values for the lock owner, and two additional types of lock ownership that must be explicitly requested. We can observe lock ownership values in the request_owner_type column of the sys.dm_tran_locks DMV. The default lock owner values are below.

TRANSACTION – Most of the locks discussed in this book are transaction-owned locks. Most of the locks that are involved in blocking and troubleshooting are transactionowned locks. The duration of transaction-owned locks is as discussed in the previous
section.

SHARED_TRANSACTION_WORKSPACE – Every connection in any database (other than master or tempdb) acquires a lock with this owner by. By observing these locks, SQL Server can tell when a database is in use. SHARED_TRANSACTION_WORKSPACE locks are held as long as a connection is using a database.

EXCLUSIVE_TRANSACTION_WORKSPACE – SQL Server acquires a lock with this owner whenever it needs exclusive access to the database. This includes activities such as dropping the database, restoring the database, or changing certain database properties, such as the READ_ONLY status. A connection cannot acquire a lock with an owner of EXCLUSIVE_TRANSACTION_WORKSPACE if any other connections have a lock owned by a SHARED_TRANSACTION_WORKSPACE and, in such cases, SQL Server generates an error message. SQL Server will hold a lock with this owner until the operation needing this lock (dropping, restoring or changing status) is completed.

The purpose of the SHARED_TRANSACTION_WORKSPACE lock owner is to prevent SQL Server from acquiring EXCLUSIVE_TRANSACTION_WORKSPACE locks, that is, to prevent a process from dropping, restoring, or changing readability status for a database, while the database is in use. The reason SQL Server does not acquire these locks for the master and tempdb databases is that these databases cannot be dropped, or have their readability status changed. In addition, we never restore tempdb, and to restore the master database, we must start the entire server in single-user mode so, again, SHARED_TRANSACTION_WORKSPACE locks are unnecessary.

The additional lock owner values are CURSOR and SESSION. We can request the former in a cursor declaration, but we will not discuss this topic further in this book. A SESSION lock is available only through user-defined locks, created with the sp_getapplock stored procedure, as will be discussed in Chapter 4.





Resource columns
Six of the columns in sys.dm_tran_locks have the resource_ prefix, and of these resource_type and resource_description are probably the most useful, providing the target resource for the requested lock (key, page, and so on) and the identity of the actual resource locked.

There is also a column called resource_database_id whose meaning should be obvious, so I won't include it in the subsequent discussion. I will mention, however, that this column returns a numerical value, and we have to translate that number to a database name, using the conversion: SELECT db_name(<resource_database_id>).

Table 2-1 shows many of the possible values for resource_type, as well as describing the information returned in the corresponding resource_description column.

DATABASE
None; the database is always indicated in the resource_database_ID column for every locked resource.

OBJECT
The object ID (which can be any database object, not necessarily a table) is reported in the resource_associated_entity_id column.

HOBT (a partition of a table or index)
None; the partition_id is reported in the resource_associated_entity_id column.

EXTENT File number:
page number of the first page of the extent.

PAGE File number:
page number of the actual table or index page.

KEY (a row of an index, either clustered or non-clustered):
A hashed value derived from all the key components and the locator. For a non-clustered index on a heap, where columns c1 and c2 are
indexed, the hash will contain contributions from c1, c2, and the RID.

RID (a row in a heap)
File number:pagenumber:slot number of the actual row.

APPLICATION
A concatenation of the database principal with access to this lock, the first 32 characters of the name given to the lock, and a hashed value
derived from the full name given to the lock.

Note that key locks and key-range locks both use KEY as the resource description because key range is considered a mode of locking, not a locking resource. However, in the output from the sys.dm_tran_locks view, we can distinguish between these types of locks by the value in the request_mode column.

For locked resources that are part of a larger entity, the resource_associated_ entity_id column in sys.dm_tran_locks displays the ID of that associated entity in the database.

The value in this column depends on the resource type:
ObjectID – The value given in this column for OBJECT resources
PartitionID – The value provided for resource types PAGE, KEY, RID, and HOBT (note that HOBT is just another way of referring to one partition of a table or index)
AllocationUnitID – Given for ALLOCATION_UNIT resources.

Of course, for some resources, such as DATABASE and EXTENT, there is no resource_associated_entity_id.




Request columns:
There are 13 columns in sys.dm_tran_locks used to identify information about the request for the lock, but two of them are documented as being for informational purposes only, not supported. Another two are only useful for DTC transactions or transactions using the MARS protocol, we won't discuss them further. Below is a list of the other nine with a basic explanation of their meaning.

request_mode – This is the lock mode discussed earlier, and indicates whether the granted or requested lock is shared (S), exclusive (X), intent shared (IX), update (U), and so on. Key-range locks, used for SERIALIZABLE isolation, appear as RangeS-U, RangeS-S and so on (see Chapter 3). For granted requests, this is the granted mode; for waiting requests, this is the mode being requested.

request_type – In SQL Server 2008, the only type of resource request tracked in sys.dm_tran_locks is for a LOCK. Future versions will include other types of resources that can be requested.

request_status – Status can be one of three values: GRANT, CONVERT, or WAIT. A status of CONVERT indicates that the requestor has already been granted a request for the same resource in a different mode and is currently waiting for an upgrade (convert) from the current lock mode to be granted. (For example, SQL Server can convert a U lock to X.) A status of WAIT indicates that the requestor does not currently hold a granted request on the resource.

request_session_id – This value is the ID of the session that has requested the lock. The owning session ID can change for distributed (DTC) and bound transactions.

request_reference_count – This value is a rough count of the number of times the same requestor has requested this resource, and applies only to resources that are not automatically released at the end of a transaction.

request_exec_context_id – This value is the execution context ID of the process that currently owns this request. A value greater than 0 indicates that this is a sub-thread used to execute a parallel query.

request_owner_type – This value refers to the owner discussed earlier, which indicates the scope of the lock. The five possible values are: TRANSACTION, SHARED_TRANSACTION_WORKSPACE, EXCLUSIVE_TRANSACTION_WORKSPACE, CURSOR and SESSION.

request_owner_id – This value is currently used only for requests with an owner of TRANSACTION, and the owner ID is the transaction ID. This column can be joined with the transaction_id column in the sys.dm_tran_active_transactions view.


lock_owner_address – This value is the memory address of the internal data structure that is used to track this request. This column can be joined with the resource_address column in sys.dm_os_waiting_tasks if this request is in the WAIT or CONVERT state. 

No comments:

Post a Comment