Module 17 18
Module 17 18
Module 17
SQL Server Concurrency
Contents:
Module Overview 17-1
Lesson 1: Concurrency and Transactions 17-2
Module Overview
Concurrency control is a critical feature of multiuser database systems; it allows data to remain consistent
when many users are modifying data at the same time. This module covers the implementation of
concurrency in Microsoft SQL Server®. You will learn about how SQL Server implements concurrency
controls, and the different ways you can configure and work with concurrency settings.
Note: Transactions and locking are closely interrelated; it is difficult to explain either topic
without reference to the other. This module covers transactions and concurrency before covering
locking, but you will find some references to locking in the description of transactions.
Objectives
At the end of this module, you will be able to:
Lesson 1
Concurrency and Transactions
This lesson focuses on how SQL Server implements concurrency and transactions. You will learn about
different concurrency models, and the strengths and weaknesses of each model. You will then learn about
different types of isolation levels and transaction internals.
Lesson Objectives
After completing this lesson, you will be able to:
Concurrency Models
Concurrency can be defined as a system’s ability to
allow multiple users to access or change shared
data simultaneously. The greater the number of
active users able to work on shared data, the
greater the level of concurrency. As the level of
concurrency increases, the likelihood of conflicting
data operations (where two or more users attempt
to access or amend the same data at the same
time) also increases.
There are two different approaches to resolving
data conflicts during concurrent operation; these
are pessimistic and optimistic concurrency.
Pessimistic Concurrency
The pessimistic concurrency model assumes that conflicting data operations will occur frequently. In this
model, locks are used to ensure that only one user can access one data item at a time. While a data item is
locked to one user, other users cannot access it. A pessimistic concurrency model exhibits the following
properties:
Data being read is locked, so that no other user can modify the data.
Data being modified is locked, so that no other user can read or modify the data.
The number of locks acquired is high because every data access operation (read/write) acquires a
lock.
The cost of preventing conflicts with locks is lower than the cost of rolling back the change, in the
case of a concurrency conflict.
Optimistic Concurrency
The optimistic concurrency model assumes that conflicting data operations will occur infrequently. In this
model, locks are not used; instead, the state of the affected data is recorded at the start of a data
operation. This state is checked again at the end of the operation, before any changes are written. If the
state has not changed, new changes are written. If the state has changed, the new changes are discarded
and the operation fails. An optimistic concurrency model exhibits the following properties:
Data being read is not locked; other users may read or modify the data.
Data being modified is not locked; other users may read or modify the data.
Before modified data is written, it is checked to confirm that it has not changed since being read; only
if it has not changed will the changes be written.
The cost of rolling back and then retrying a change is lower than the cost of holding locks.
SQL Server supports implementations of both optimistic concurrency and pessimistic concurrency.
Pessimistic concurrency is the default concurrency model for the database engine. The In-Memory OLTP
Engine uses a type of optimistic concurrency called row versioning; it does not implement pessimistic
concurrency.
Concurrency Problems
There are several categories of problems that may
occur when concurrency control is lacking or
insufficient, and multiple sessions attempt to
access or change the same data item.
Dirty Read
A dirty read occurs when one transaction reads a
row that is in the process of being modified by
another transaction. The reading transaction reads
uncommitted data that may be changed later by a
transaction modifying the data.
For example, user A changes a value from x to y,
but does not finalize the change by committing the transaction. A second user, user B, reads the updated
value y and performs processing based on this value. User A later changes the value again, from y to z,
and commits the transaction. User B reads the uncommitted (dirty) value.
Lost Update
A lost update occurs when one or more transactions simultaneously updates the same row, based on the
same initial value. When this happens, the last transaction to update the row overwrites the changes made
by other transaction(s), resulting in lost data.
17-4 SQL Server Concurrency
For example, user C and user D select value x to update. User C first updates the value from x to y, and
then user D updates the value x to z. The modifications made by user A are overwritten by user B,
resulting in data loss.
Non-repeatable Read
A non-repeatable read occurs when a transaction reads different values for the same row each time the
row is accessed. This happens when data is changed by another transaction in between two SELECT
statements.
For example, user E begins a transaction that contains two similar SELECT statements, s1 and s2. The
SELECT statement s1 reads value x, and then does some processing. Another user, user F, modifies value x
to y while user E is executing other queries. When user E subsequently executes s2, the value y is returned
instead of the initial x.
Phantom Read
A phantom read is a variation of a non-repeatable read. Phantom reads occur when one transaction
carries out a DELETE operation or an INSERT operation against a row that belongs to the range of rows
being read by another transaction.
For example, user G has two similar SELECT statements, s1 and s2, within a transaction; the SELECT
statement s1 reads the count of rows as n, and then does other processing. Meanwhile, another user, user
H, deletes a row from the range of rows being read by select statement s1 and s2. When user G returns to
execute s2, the row count is n-1. The SELECT statement s1 returns a phantom read for a row that does not
exist at the end of user G’s transaction.
Double Read
A double read occurs when a transaction reads the same row value twice when reading a range of rows.
This happens when the row value that defines the range is updated by another transaction while the
range is being read.
For example, user I executes a SELECT statement that returns rows with values in a range a to z, that is
implemented as an index scan. After the scan has read rows with value a, but before the scan completes,
another user, user J, updates a row with value a to value z. The updated row is read again when the scan
reaches rows with value z.
Note: It is also possible for this issue to miss a row, but this is still referred to as a double
read problem. In the example, a row could be updated from value z to value a while the scan was
running.
Developing SQL Databases 17-5
o Fetches the committed data present at the time the transaction started.
READ UNCOMMITTED
READ UNCOMMITTED is the lowest level of isolation available in SQL Server. The READ UNCOMMITTED
isolation level has the following properties:
Readers do not block writers, and writers do not block readers; however, writers do block writers.
All of the concurrency problems (dirty reads, non-repeatable reads, double reads, and phantom
reads) can occur.
READ COMMITTED
READ COMMITTED is the SQL Server default isolation level. The READ COMMITTED isolation level has the
following properties when the READ_COMMITTED_SNAPSHOT database option is OFF (the default for
SQL Server installations):
Read locks are acquired and held until the end of the statement.
Because read locks are held until the end of the statement, data can be changed by other
transactions between individual statements within the current transaction, resulting in non-repeatable
reads, double reads, and phantom reads.
When the READ_COMMITTED_SNAPSHOT database option is ON (the default for Azure SQL Database),
the READ COMMITTED isolation level has the following properties:
Row versioning is used to provide statement-level read consistency. Because each statement in a
transaction executes, a snapshot of old data is taken and stored in version store. The snapshot is
consistent until the statement finishes execution.
Read locks are not held because the data is read from the version store, and not from the underlying
object.
Dirty reads do not occur because a transaction reads only committed data, but non-repeatable reads
and phantom reads can occur during a transaction.
REPEATABLE READ
REPEATABLE READ has the following properties:
Read locks are acquired and held until the end of the transaction. Therefore, a transaction cannot
read uncommitted data and cannot modify the data being read by other transactions until that
transaction completes.
Eliminates non-repeatable reads. Phantom reads and double reads still occur. Other transactions can
insert or delete rows in the range of data being read.
Not supported on FILESTREAM enabled databases.
SERIALIZABLE
SERIALIZABLE is the highest level of isolation available in SQL Server. It has the following properties:
Range locks are acquired on the range of values being read and are held until the end of the
transaction.
Transactions cannot read uncommitted data, and cannot modify the data being read by other
transactions until the transaction completes; another transaction cannot insert or delete the rows in
the range of rows being read.
SNAPSHOT
SNAPSHOT isolation is based on an optimistic concurrency model. SNAPSHOT isolation has the following
properties:
Uses row versioning to provide transaction-level read consistency. A data snapshot is taken at the
start of the transaction and remains consistent until the end of the transaction.
Transaction-level read consistency eliminates dirty reads, non-repeatable reads, and phantom reads.
For more information on transaction isolation levels, see the topic SET TRANSACTION ISOLATION LEVEL
(Transact-SQL) in Microsoft Docs:
Read performance may degrade because the set of versioned rows ages and large version chains
must be scanned.
SNAPSHOT isolation may result in transaction rollback because of update conflict. Applications may
need to be modified to handle update conflicts.
Other points you should consider include:
SNAPSHOT isolation does not affect queries with lock hints. The lock hints still apply.
Transactions
A transaction is considered to be one or more
Transact-SQL statements that are logically
grouped into a single unit of work. A transaction
might be made up of multiple statements;
changes made to data by these statements are
applied to the database only when the transaction
completes successfully. A transaction must adhere
to the ACID principles:
Isolation. A transaction must have a view of the data independent of any other concurrent
transaction; a transaction should not see data in an intermediate state.
Durability. Data changes must be persisted in case of a system failure.
Auto-commit mode
Auto-commit is the default transaction management mode in SQL Server. A transaction is either
committed or rolled back after completion. If a statement completes successfully without any error, it is
committed. If it encounters errors, it is rolled back. Auto-commit mode is overridden when a user initiates
an explicit transaction or when implicit transaction mode is enabled.
COMMIT TRANSACTION. Marks the successful completion of a transaction. The modifications made
to a database are made permanent; the resources held by a transaction are released.
When an explicit transaction completes, the connection returns to the transaction mode it was using
before the start of the explicit transaction.
For more information on transaction control statements in explicit transaction mode, see the topic
Transaction Statements (Transact-SQL) in Microsoft Docs:
Implicit transaction is a session level setting and can be changed by setting the
IMPLICIT_TRANSACTION option to ON/OFF.
SQL Server automatically starts an implicit transaction when any of the following statements are
executed: ALTER TABLE, CREATE, DELETE, DROP, FETCH, GRANT, INSERT, OPEN, REVOKE, SELECT,
TRUNCATE TABLE, UPDATE.
For more information about implicit transaction mode, see the topic SET IMPLICIT_TRANSACTIONS
(Transact-SQL) in Microsoft Docs:
The transaction mode is set at the connection level. If a connection changes from one transaction mode
to another, other active connections are not affected.
Naming Transactions
Transaction names are optional, and have no
effect on the behavior of SQL Server; they act
purely as labels to assist developers and DBAs in
understanding Transact-SQL code.
Nesting Transactions
Explicit transactions can be nested; you can issue a BEGIN TRANSACTION command inside an open
transaction. Only the outermost transaction has any effect; if the outermost transaction is committed, all
the nested transactions are committed. If the outermost transaction is rolled back, all the nested
transactions are rolled back. The level of transaction nesting is tracked by the @@TRANCOUNT function,
which is maintained at connection level:
Each COMMIT statement decrements @@TRANCOUNT by one. The COMMIT that reduces
@@TRANCOUNT to zero commits the outermost transaction.
A ROLLBACK statement rolls back the outer transaction and reduces @@TRANCOUNT to zero.
17-10 SQL Server Concurrency
Terminating Transactions
In addition to an explicit COMMIT or ROLLBACK, a transaction can be terminated for the following
reasons:
Resource error. If a transaction fails because of a resource error such as lack of disk space, SQL Server
automatically rolls back the transaction to maintain data integrity.
SET XACT_ABORT. When the connection-level SET XACT_ABORT setting is ON, an open transaction
is automatically rolled back in the event of a runtime error. When XACT_ABORT is OFF, a statement
that causes an error is normally rolled back, but any open transaction will remain open.
Connection closure. If a connection is closed, all open transactions are rolled back.
For more information on SET XACT_ABORT, see the topic SET XACT_ABORT (Transact-SQL) in Microsoft
Docs:
Savepoints
You can also create a save point partway through the transaction. This is a named point within a
transaction. You then use a ROLLBACK statement to revert to the save point, which means you can retry
without having to start the entire transaction again. You set save points using the SAVE TRANSACTION
key words. You can specify a name up to 32 characters, or a variable holding the name of the save point.
You can then use the ROLLBACK command, together with the name of the save point, to return to the
save point in the event of an error. Typically the save point would be created in the TRY block, and the
ROLLBACK to the save point would be included in the CATCH block of an error handling construct.
The following code fragments show how to name a save point, and how to refer to the named save point
in the event of a ROLLBACK:
SAVEPOINT
SAVE TRANSACTION SavePointName;
Avoid user input. Avoid user interaction during a transaction. This might add unnecessary delay,
because a user may open a transaction and go out for a break. The transaction will hold locks until
the user returns to complete the transaction or the transaction is killed. Other transactions requiring
locks on the same resource will be blocked during this time.
Open a transaction only when necessary. If possible, avoid opening a transaction when browsing
through data. Do the preliminary data analysis and then open a transaction to perform any necessary
data modification.
Developing SQL Databases 17-11
Access only relevant data. Access only the relevant data within a transaction. This reduces the
number of locks, so reducing the blocking and deadlocks.
Use the appropriate transaction isolation level. Not all applications require high level isolation
level, such as repeatable read and serializable. Many applications work well with the default
repeatable read isolation.
Demonstration Steps
Preparation
3. In the User Account Control dialog box, click Yes, and then wait for the script to finish.
4. Start SQL Server Management Studio and connect to your Azure instance of the AdventureWorksLT
database engine instance using SQL Server authentication.
5. In the Login box, type Student, in the Password box, type Pa55w.rd, and then click Connect.
7. Open the Demo 1a.sql and the Demo 1b.sql script files; open these files in different query windows,
because you will be switching between them.
Dirty Reads
1. In the Demo 1a.sql script file, under the comment that begins Step 1, select the code, and then click
Execute to check the current settings for SNAPSHOT isolation.
2. Under the comment that begins Step 2, select the code, and then click Execute to view the current
state of the row used in this demonstration.
3. In the Demo 1b.sql script file, under the comment that begins Query 1, select the code, and then
click Execute.
4. In the Demo 1a.sql file, under the comment that begins Step 3, select the code, and then click
Execute to demonstrate READ UNCOMMITTED isolation.
5. Under the comment that begins Step 4, select the code, and then click Execute to demonstrate
READ COMMITTED isolation. The query will wait until you complete the next step.
6. In the Demo 1b.sql file, under the comment that begins Query 2, select the code, and then click
Execute.
17-12 SQL Server Concurrency
7. In the Demo 1a.sql script file, note that the query under Step 4 (which was already running) has now
returned a result.
Non-repeatable Reads
1. In the Demo 1a.sql script file, under the comment that begins Step 5, select the first five lines of
code, and then click Execute.
2. In the Demo 1b.sql file, under the comment that begins Query 3, select the code, and then click
Execute.
3. In the Demo 1a.sql file, under the comment that begins Step 5, select the final four lines of code,
and then click Execute to demonstrate a non-repeatable read.
4. Under the comment that begins Step 6, select the first six lines of code, and then click Execute.
5. In the Demo 1b.sql file, under the comment that begins Query 4, select the code, and then click
Execute. Note that this query will not return until you complete the next step, because REPEATABLE
READ holds a lock on the affected row.
6. In the Demo 1a.sql script file, under the comment that begins Step 6, select the final four lines of
code, and then click Execute to demonstrate that REPEATABLE READ isolation prevents a non-
repeatable read.
Phantom Read
1. In the script Demo1a.sql that begins Step 7, select the first six lines of code, and then click Execute.
2. In the Demo 1b.sql script file, under the comment that begins Query 5, select the code, and then
click Execute.
3. In the Demo 1a.sql file, under the comment that begins Step 7, select the final four lines of code,
and then click Execute to demonstrate that READ COMMITTED isolation allows a phantom read.
2. In the Demo 1b.sql script file under the comment that begins Query 6, select the code, and then
click Execute. Note that this query will not return until you complete the next step, since
SERIALIZABLE holds a lock on the affected table.
3. In the Demo 1a.sql script file, under the comment that begins Step 8, select the final four lines of
code, and then click Execute to demonstrate that SERIALIZABLE isolation prevents a phantom read.
Snapshot Isolation
1. In Demo 1a.sql, under the comment that begins Step 9, select the first eight lines of code, and then
click Execute. This can take up to 30 minutes to complete.
2. Select the last three lines of code under Step 9, and then click Execute. Note the locks.
3. In the Demo 1b.sql script file, under the comment that begins Step 6, select the code, and then click
Execute. Note that the query does not complete.
4. In the Demo 1a.sql script file, under the comment that begins Query 10, select the code, and then
click Execute. Note the locks.
5. In the Demo 1a.sql script file, under the comment that begins Step 11, select the code, and then
click Execute. Note that the query in Demo 1b aborted, demonstrating the behavior of SNAPSHOT
isolation.
6. Close SQL Server Management Studio without saving any changes.
Developing SQL Databases 17-13
Pessimistic concurrency
Optimistic concurrency
17-14 SQL Server Concurrency
Lesson 2
Locking Internals
SQL Server uses locks to ensure the consistency of data during a transaction. This lesson discusses the
details of the locking architecture used by SQL Server, how locks are used during the life of a transaction,
and the various methods available to you to influence the default locking behavior.
Lesson Objectives
At the end of this lesson, you will be able to:
Understand deadlocks.
Explain latches and spinlocks.
Locking Architecture
In a hypothetical database system, the least
sophisticated locking architecture possible is to
allow locks only at database level. Every user
reading or writing data would lock the entire
database, preventing access by any other user
until the change was complete. While this
approach ensures data is consistent, it prohibits
concurrent database activity.
Lock Manager
Internally, locks are automatically managed by the lock manager, a component of the database engine.
When the database engine processes a Transact-SQL statement, the Query Processor subcomponent
determines the resources that will be accessed. The Query Processor also determines the type of locks to
acquire, based on the type of data access (read or write) and the transaction isolation level setting. The
Query Processor then requests these locks from the lock manager. The lock manager grants the locks if no
conflicting locks are being held by other transactions.
Locks are in-memory structures; the lock manager maintains a memory structure for each lock, called a
lock block, which records the lock type and the resource that is locked. Each lock block will be linked to
one or more lock owner blocks; the lock owner block links a lock to the process requesting the lock. The
lock manager also maintains a lock hash table, to track locked resources more efficiently.
When a SQL Server instance starts, lock manager acquires sufficient memory to support 2,500 locks. If the
total number of locks exceeds 2,500, more memory is allocated dynamically to lock manager.
For more information on locking in SQL Server, see the topic SQL Server Transaction Locking and Row
Versioning Guide on MSDN:
SQL Server acquires locks at any of the following levels, ordered here from lowest grain to highest grain.
The first two items (RID and KEY) are of equivalent grain:
RID. RID stands for row id. A row id is a lock on a single row in a heap (table without clustered index).
PAGE. A lock on an 8 KB page in a database, such as a data or index page. If a page is locked, all of
the data rows contained in the page are locked.
EXTENT. A lock on a 64 KB extent (a block of eight pages). If an extent is locked, all of the pages in
the extent are locked.
HoBT. HoBT stands for heap or b-tree. A lock protecting a b-tree (index), or the heap data pages in a
table that does not have a clustered index. All the extents that make up the heap or b-tree are locked.
OBJECT. Typically, a lock on a table. If a table is locked, all of the associated data and index pages are
also locked.
17-16 SQL Server Concurrency
FILE. A lock on a database file. If a file is locked, all of the objects it contains are locked.
DATABASE. A lock on an entire database. All the objects in the database are also locked.
The objects in this list make up a hierarchy; databases are composed of files, files contain tables, and
tables are in turn made up of extents, pages, and rows. To fully protect a resource during the processing
of a command, a process might acquire locks at multiple levels of the resource hierarchy. For example,
when processing a command that affects a single row in a table, locks might be acquired on the affected
row, the page in which the row is stored, the page’s extent, and the table to which the row belongs. This
both fully protects the table and simplifies the detection of locking conflicts with other concurrent
processes that may hold locks on different rows in the same table.
Lock Escalation
Lock escalation occurs when many fine-grained
locks held by a transaction on a single resource
are converted to a single coarser-grained lock on
the same resource. Lock escalation is used to limit
the total number of locks the lock manager must
manage; the cost being that lock escalation might
reduce concurrency.
Lock escalation can also occur when the memory structures maintained by the lock manager consume
more than 40 percent of the available memory.
You can control lock escalation behavior for individual tables by using the ALTER TABLE SET
LOCK_ESCALATION command. LOCK_ESCALATION can be set to one of three values:
TABLE. The default value. When lock escalation occurs, locks are always escalated to table level,
whether or not the table is partitioned.
AUTO. If the table is partitioned when lock escalation occurs, locks can be escalated to partition level.
If the table is not partitioned, locks are escalated to table level.
DISABLE. Prevents lock escalation occurring in most cases. Table locks might still occur, but will be
less frequent.
For more information on controlling lock escalation behavior, see the topic ALTER TABLE (Transact-SQL) in
Microsoft Docs:
Lock escalation behavior can also be controlled at session level or instance level by use of trace flags:
Trace flag 1224 disables lock escalation, based on the number of locks held on a resource. Lock
escalation due to memory pressure can still occur.
Trace flag 1211 disables lock escalation completely, whether due to the number of locks held on a
resource or due to memory pressure. Disabling lock escalation can have a severe effect on
performance and is not recommended.
For more information on trace flags 1224 and 1211, see the topic Trace Flags (Transact-SQL) in Microsoft
Docs:
Lock Modes
SQL Server locks resources using different lock
modes. The lock modes determine how accessible
a resource is to other concurrent transactions.
Intent lock. An intent lock is not a locking mode in its own right—it acts as a qualifier to other lock
modes. Intent locks are used on a data item to indicate that a subcomponent of the data item is
locked; for instance, if a row in a table is locked with a shared lock, the table to which the row belongs
would be locked with an intent shared lock. Intent locks are discussed in more detail in the next topic.
Key-range locks. Key-range locks are used by transactions using the SERIALIZABLE isolation level to
lock ranges of rows that are implicitly read by the transaction; they protect against phantom reads.
Schema lock. Schema locks are used when an operation dependent on the table schema is executed.
There are two types of schema lock:
o Schema modification lock. Schema modification locks are acquired when a data definition
language (DDL) operation is being performed against a table, such as adding or dropping a
column.
o Schema stability lock. Schema stability locks are used during query compilation to prevent
transactions that modify the underlying database schema. Schema stability locks are compatible
with all other lock types (including exclusive locks).
Conversion lock. A conversion lock is a specialized type of intent lock used to manage the transition
between data lock modes. Conversion locks appear in three types:
o Shared with intent exclusive. Used when a transaction holds a mixture of shared locks and
exclusive locks on subobjects of the locked object.
o Shared with intent update. Used when a transaction holds a mixture of shared locks and update
locks on subobjects of the locked object.
o Update with intent exclusive. Used when a transaction holds a mixture of exclusive locks and
update locks on subobjects of the locked object.
Bulk update lock. Bulk update locks can optionally be acquired when data is bulk inserted into a
table using a bulk command such as BULK INSERT. A bulk update lock can only be acquired if no
other incompatible lock types are held on the table.
Locks held by active transactions can be viewed by using the sys.dm_tran_locks dynamic management
view (DMV). DMVs use abbreviations for lock mode names, summarized in the following table:
S Shared
U Update
X Exclusive
IS Intent Shared
IU Intent Update
IX Intent Exclusive
BU Bulk Update
For more information on the sys.dm_tran_locks DMV, see the topic sys.dm_tran_locks (Transact-SQL) in
Microsoft Docs:
sys.dm_tran_locks (Transact-SQL)
http://aka.ms/jf98cd
Note: Lock compatibility gives an insight into the differences in behavior between the
different isolation levels you learned about in the previous topic; the more pessimistic isolation
levels acquire and hold locks that are less compatible with other lock types.
When processes wait for incompatible lock types to be released, they wait in a first-in, first-out queue. If
there are already processes queuing for a resource, a process seeking to acquire a lock on the same
resource must join the end of the queue, even if the mode of the lock it seeks to acquire is compatible
with the current lock on the resource. On busy resources, this prevents processes seeking less compatible
lock modes from waiting indefinitely when other, more compatible, lock modes are in use.
17-20 SQL Server Concurrency
For a full lock compatibility matrix, see the topic Lock Compatibility (Database Engine) on Microsoft
TechNet (note that this page comes from the SQL Server 2008 R2 documentation; Microsoft has not
published a recent version of this matrix):
The following steps are involved when modifying data in SQL Server:
A user or an application sends the UPDATE query to SQL Server.
The database engine receives the update request and locates the data pages to be updated in the
cache—or reads the data pages from the storage subsystem into cache.
The database engine tries to grant the lock on the necessary data to the user’s session:
o If any transaction already has an incompatible lock on the affected data, the UPDATE query waits
for the existing lock to be released.
o Because this UPDATE statement is highly selective (affecting only two rows) the database engine
uses row level locking to acquire an update lock on each of the two rows being modified.
The following additional locks are acquired to secure the pages and the table in question:
o Two intent-exclusive page level locks (one for each page, since the rows are in different pages).
SQL Server starts the data modification. The steps are as follows:
o The data modification is made (in the cache). At the same time, the update lock is converted to
an exclusive lock.
Developing SQL Databases 17-21
Locking Hints
There might be instances where you need to
influence locking behavior; several table hints are
available that help you adjust the locking of
individual tables during a single Transact-SQL
statement. You can use hints to influence:
You can specify multiple hints for a table—the hints should be comma-separated in the brackets of the
WITH command.
Best Practice: In general, it is best to avoid locking hints and allow the SQL Server Query
Optimizer to select an appropriate locking strategy. Be sure to regularly review any locking hints
you use; confirm that they are still appropriate.
ROWLOCK. Row locks should be acquired where page or table locks would normally be used.
PAGLOCK. Page locks should be acquired where row or table locks would normally be used.
TABLOCK. A table lock should be acquired where row or page locks would normally be used.
READCOMMITTED. Use the READ COMMITTED isolation level. Locks or row versioning are used,
depending on the value of the READ_COMMITTED_SNAPSHOT database setting.
17-22 SQL Server Concurrency
READCOMMITTEDLOCK. Use the READ COMMITTED isolation level, acquiring locks. The value of the
READ_COMMITTED_SNAPSHOT database setting is ignored.
For more information on table hints—including those that control locking—see the topic Table Hints
(Transact-SQL) in Microsoft Docs:
Use the TABLOCK hint to speed up bulk insert operations. TABLOCK is only compatible with itself.
This allows multiple bulk inserts to be made in parallel into a single table, while preventing other
processes to update or modify the records. This considerably improves bulk insert performance.
Avoid using the NOLOCK or READUNCOMMITTED hint to resolve reader-writer blocking; consider
setting READ_COMMITTED_SNAPSHOT to ON or using the SNAPSHOT isolation level. The NOLOCK
and READUNCOMMITTED hints are only suitable in environments where the effects of the READ
UNCOMMITTED isolation level (documented in the previous lesson) are acceptable.
Use ROWLOCK or UPDLOCK hints to reduce deadlocks in the REPEATABLE READ isolation level.
Deadlock Internals
A deadlock occurs when two or more transactions
block one another by attempting to acquire a lock
on a resource that is already locked by the other
transaction(s) with an incompatible lock mode. For
example:
Transaction B requests an exclusive lock on table T1. It waits on transaction A to release the shared
lock it holds on Table T1. A deadlock has occurred.
Deadlock Resolution
The Lock Monitor process is responsible for detecting deadlocks. It periodically searches for the tasks
involved in a deadlock. The search process has the following properties:
The default interval between deadlock detection searches for five seconds.
As soon as a deadlock is found, the deadlock detection search will run again immediately.
When deadlocks are detected, the deadlock detection search interval is reduced to as little as 100
milliseconds, depending on the deadlock frequency.
When a deadlock is detected, the Lock Monitor ends the deadlock by choosing one of the thread as the
deadlock victim. The deadlock victim command is forcefully terminated; the transaction is rolled back, and
the error 1205 is returned to the application. This releases the locks held by the deadlock victim, allowing
the other transactions to continue with their work.
If all the deadlocked transactions have the same deadlock priority, the transaction that is estimated to
be the least expensive to roll back is chosen as the deadlock victim.
If the deadlocked transactions have a different deadlock priority, the transaction with the lowest
deadlock priority is chosen as the deadlock victim.
Deadlock Priority
You can specify the deadlock priority of a transaction by using the SET DEADLOCK_PRIORITY command.
You can set deadlock priority to an integer value between -10 (the lowest priority) and 10 (the highest
priority)—or you can use a text value:
LOW. Equivalent to the integer value -5.
For more information on setting deadlock priority, see the topic SET DEADLOCK_PRIORITY (Transact-SQL)
in Microsoft Docs:
Analyze Deadlocks
You can use SQL Server Profiler to analyze deadlocks. The Locks section of SQL Server Profiler includes a
Deadlock graph event class which you can add to your trace. This is a graphical representation of the
deadlock, showing the statements involved in the deadlock. Add data about the deadlock to a Deadlock
XML file, and you can choose whether to write all deadlock events to one files, or to separate files. The
deadlock data can then be viewed graphically by opening the file in SSMS.
For more information about analyzing deadlocks using SQL Server Profiler, see Microsoft Docs:
Analyze Deadlocks with SQL Server Profiler
https://aka.ms/nn6oel
17-24 SQL Server Concurrency
Latches
Latches are a lightweight locking mechanism used
by the storage engine to ensure the consistency of
in-memory data structures, such as data pages
and non-leaf pages in a b-tree. Latches are
managed internally by SQL Server and cannot be
controlled by users. Latches are broadly divided
into three types:
I/O latches. Used to manage outstanding I/O operations against pages in the Buffer Pool, I/O latches
ensure that pages are read only once from I/O into the Buffer Pool.
Buffer latches. Used to prevent concurrent processes from making conflicting changes to pages in
the Buffer Pool.
Non-buffer latches. Used to protect shared data structures held outside the Buffer Pool.
When a process waits for a latch, the duration of the wait is recorded in the sys.dm_os_wait_stats DMV:
Non-buffer latches are summarized as wait types with names starting LATCH_. A complete list of all
non-buffer latch types can be found in the sys.dm_os_latch_stats DMV.
For more information on the sys.dm_os_wait_stats DMV, see the topic sys.dm_os_wait_stats (Transact-
SQL) in Microsoft Docs:
sys.dm_os_wait_stats (Transact-SQL)
http://aka.ms/kvkoru
For more information on the sys.dm_os_latch_stats DMV, see the topic sys.dm_os_latch_stats (Transact-
SQL) in Microsoft Docs:
sys.dm_os_latch_stats (Transact-SQL)
http://aka.ms/im1px3
Spinlocks
Spinlocks are very lightweight locking structures used when a process needs to lock an object in memory
for a very short time. A process waiting to acquire a spinlock will go into a loop for a period, checking
repeatedly whether the lock is available—as opposed to moving onto a waiter list and yielding the CPU
immediately. SQL Server uses spinlocks to protect objects such as hash buckets in the lock manager’s lock
hash table.
Some contention for spinlocks is expected on busy SQL Server instances; spinlock contention should only
be considered a problem when it causes significant CPU overhead. Performance problems can be caused
by contention for spinlocks, but this is a relatively rare occurrence.
Developing SQL Databases 17-25
For more information on diagnosing and resolving performance problems caused by spinlock contention,
see the Microsoft paper Diagnosing and Resolving Spinlock Contention on SQL Server. Note that this paper
was written in reference to SQL Server 2008 R2:
Demonstration Steps
1. Start SQL Server Management Studio and connect to the MIA-SQL database engine instance using
Windows authentication.
4. In the Demo 2a - lock hints 1.sql script file, under the comment that begins Step 3, select the code,
and then click Execute to show the current isolation level.
5. Under the comment that begins Step 4, select the first three lines of code, and then click Execute to
demonstrate the locks held by a transaction using READ UNCOMMITTED isolation.
6. Under the comment that begins Step 4, select the remaining five lines of code, and then click
Execute.
7. Under the comment that begins Step 5, select the first three lines of code, and then click Execute to
demonstrate the locks held by a transaction using REPEATABLE READ isolation.
8. Under the comment that begins Step 5, select the remaining five lines of code, and then click
Execute.
9. Under the comment that begins Step 6, select the first three lines of code, and then click Execute to
demonstrate the locks held by a transaction using REPEATABLE READ isolation and a
READCOMMITTED locking hint.
10. Under the comment that begins Step 6, select the remaining five lines of code, and then click
Execute.
11. Under the comment that begins Step 7, select the first three lines of code, and then click Execute to
demonstrate the locks held by a transaction using READ COMMITTED isolation and a TABLOCKX
locking hint.
12. Under the comment that begins Step 7, select the remaining five lines of code, and then click
Execute.
13. Under the comment that begins Step 8, select the first three lines of code, and then click Execute to
demonstrate the locks held by a transaction using REPEATABLE READ isolation and a TABLOCKX
locking hint.
14. Under the comment that begins Step 8, select the remaining five lines of code, and then click
Execute.
15. In the Demo 2b - lock hints 2.sql script file, under the comment that begins Query 1, select the
code, and then click Execute.
17-26 SQL Server Concurrency
16. In the Demo 2a - lock hints 1.sql script file, under the comment that begins Step 9, select the code,
and then click Execute to demonstrate that the statement waits.
17. Allow the query to wait for a few seconds, and then on the Query menu, click Cancel Executing
Query.
18. Under the comment that begins Step 10, select the code, and then click Execute to demonstrate the
behavior of the READPAST hint.
19. In the Demo 2b - lock hints 2.sql script file, under the comment that begins Query 2, select the
code, and then click Execute to close the open transaction.
Exclusive (X)
Shared (S)
Objectives
After completing this lab, you will be able to:
2. Execute the query under the comment that begins Task 1 to clear wait statistics.
Results: After this exercise, the AdventureWorks database will be configured to use the SNAPSHOT
isolation level.
Developing SQL Databases 17-29
2. Switch to SSMS and to the MIA-SQL - Activity Monitor tab. In the Resource Waits section, note the
value of Cumulative Wait Time (sec) for the Lock wait type.
3. Close the PowerShell window where the workload was executed.
2. Rerun the query under the comment that begins Task 2 to clear wait statistics.
2. Return to the MIA-SQL - Activity Monitor tab. In the Resource Waits section, note the value of
Cumulative Wait Time (sec) for the Lock wait type.
3. Compare this value to the value you noted earlier in the exercise.
Results: After this exercise, the AdventureWorks database will use partition level locking.
17-30 SQL Server Concurrency
Review Question(s)
SERIALIZABLE
READ UNCOMMITTED
REPEATABLE READ
READ COMMITTED
18-1
Module 18
Performance and Monitoring
Contents:
Module Overview 18-1
Lesson 1: Extended Events 18-2
Module Overview
This module looks at how to measure and monitor the performance of your SQL Server® databases. The
first two lessons look at SQL Server Extended Events, a flexible, lightweight event-handling system built
into the Microsoft® SQL Server Database Engine. These lessons focus on the architectural concepts,
troubleshooting strategies and usage scenarios.
This module also describes tools and techniques you can use to monitor performance data, and to create
baselines.
Objectives
After completing this module, you will be able to:
Use DMVs and Performance Monitor to create baselines and gather performance metrics.
18-2 Performance and Monitoring
Lesson 1
Extended Events
SQL Server Extended Events is a flexible, lightweight event-handling system built into the Microsoft SQL
Server Database Engine. This lesson focuses on the architectural concepts, troubleshooting strategies, and
usage scenarios of Extended Events.
Lesson Objectives
When you have completed this lesson, you will be able to:
SQL Trace
SQL Trace is a server-side, event-driven activity
monitoring tool; it can capture information about
more than 150 event classes. Each event returns
data in one or more columns and you can filter
column values. You configure the range of events
and event data columns in the trace definition.
You can also configure the destination for the
trace data, a file or a database table, in the trace
definition.
SQL Trace is included in SQL Server 7.0 and later versions.
As established parts of the SQL Server platform, SQL Server Profiler and SQL Trace are familiar to many
SQL Server administrators.
Note: SQL Trace and SQL Server Profiler are marked for deprecation and will be removed in
future versions of SQL Server. Extended Events is now the recommended activity tracing tool.
Because SQL Trace is marked for deprecation, it does not include event classes for many features
added in SQL Server 2012 onwards.
Extended Events
Like SQL Trace, Extended Events is an event-driven activity monitoring tool; however, it attempts to
address some of the limitations in the design of SQL Trace by following a loose-coupled design pattern.
Events and their targets are not tightly coupled; any event can be bound to any target. This means that
data processing and filtering can be carried out independently of data capture. In most cases, this results
in Extended Events having a lower performance overhead than an equivalent SQL Trace.
Developing SQL Databases 18-3
With Extended Events, you can define sophisticated filters on captured data. In addition to using value
filters, you can filter events by sampling, and data can be aggregated at the point it is captured. You can
manage Extended Events either through a GUI in SQL Server Management Studio (SSMS) or by using
Transact-SQL statements.
You can integrate Extended Events with the Event Tracing for Windows (ETW) framework, so that you can
monitor SQL Server activity alongside other Windows® components.
Extended Events was introduced in SQL Server 2008; since the deprecation of SQL Trace and SQL Server
Profiler was announced with the release of SQL Server 2012, many features introduced in SQL Server 2012,
2014, 2016, and 2017 can only be traced using Extended Events.
However, the additional flexibility of Extended Events comes at the cost of greater complexity.
A list of sessions is maintained by the Extended Events engine. You can define and modify sessions using
Transact-SQL or in SSMS. You can view data collected by active sessions using Transact-SQL—in which
case the data is presented in XML format—or using SSMS.
18-4 Performance and Monitoring
Packages
Packages act as containers for the Extended Events
objects and their definitions; a package can
expose any of the following object types:
Events
Predicates
Actions
Targets
Types
Maps
Packages are contained in a module that exposes them to the Extended Events engine. A module can
contain one or more packages, and can be compiled as an executable or DLL file.
A complete list of packages registered on the server can be viewed using the sys.dm_xe_packages DMV:
sys.dm_xe_packages
SELECT * FROM sys.dm_xe_packages;
sys.dem_xe_packages (Transact-SQL)
http://aka.ms/i4j6vf
sys.dm_xe_objects; events
SELECT * FROM sys.dm_xe_objects
WHERE object_type = 'event';
Developing SQL Databases 18-5
Events are defined by the Event Tracing for Windows model—this means that SQL Server Extended Events
can be integrated with ETW. Like ETW events, Extended Events is categorized by:
Channel. The event channel identifies the target audience for an event. These channels are common
to all ETW events:
When you add, amend or remove an event from a package, you must refer to it with a two-part name:
packagename.eventname.
For more information on sys.dm_xe_objects, see Microsoft Docs:
sys.dm_xe_objects (Transact-SQL)
http://aka.ms/bwkcmu
Actions
Actions are responses to an event; you can use these responses to collect supplementary information
about the context of an event at the time that it occurs. Each event may have a unique set of one or more
actions associated with it. When an event occurs, any associated actions are raised synchronously.
Note: Actions do not allow you to define responses to an event. Instead, actions are
additional steps that occur within the Extended Events engine when an event is triggered. Most
actions provide more data to be collected about an event.
o Collect database ID
o Collect session ID
All available actions can be viewed in the DMV sys.dm_xe_objects under the object_type value action:
sys.dm_xe_objects; actions
SELECT * FROM sys.dm_xe_objects
WHERE object_type = 'action';
Predicates
Predicates are logical rules with which events can be selectively captured, based on criteria you specify.
Predicates divide into two subcategories:
Predicate comparisons. Comparison operators, such as “equal to”, “greater than”, and “less than”,
which may make up a predicate filter. All predicate comparisons return a Boolean result (true or false).
Predicate sources. Data items that may be used as inputs to predicate comparisons. These are similar
to the column filters available when defining a SQL trace.
In addition to building logical rules, predicates are capable of storing data in a local context, which means
that predicates based on counters can be constructed; for example, every n events or every n seconds.
Predicates are applied to an event using a WHERE clause—this functions like the WHERE clause in a
Transact-SQL query.
All available predicates can be viewed in the DMV sys.dm_xe_objects under the object_type values
pred_source and pred_compare.
sys.dem_xe_objects; predicates
SELECT * FROM sys.dm_xe_objects
WHERE object_type LIKE 'pred%'
ORDER BY object_type, name;
Event pairing. Tracks when events that normally occur in pairs (for example, lock acquired and lock
released) do not have a matching pair—asynchronous.
Histogram. A more complex counter that partitions counts by an event or action value—
asynchronous.
The design of Extended Events is such that an event will only be written once to a target, even if multiple
sessions are configured to send that event to the same target.
All available targets can be viewed in the DMV sys.dm_xe_objects under the object_type value target:
sys.dm_xe_objects; targets
SELECT * FROM sys.dm_xe_objects
WHERE object_type = 'target';
Sessions
A session links one or more events to one or more targets. You can configure each event in a session to
include one or more actions, and to be filtered with one or more predicates. Once defined, a session can
be started or stopped as required; it is possible to configure a session to start when the database engine
starts.
A session may include events from more than one package. Sessions are isolated from one another;
multiple sessions may use the same events and targets in different ways, without interfering with one
another.
A session is configured with a buffer in which event data is held while a session is running, before it is
dispatched to the session targets. The size of this buffer is configurable, as is a dispatch policy (how long
data will be held in the buffer). You can also configure whether or not to permit data loss from the buffer
if event data arrives faster than it can be processed and dispatched to the session target.
All active Extended Events sessions can be viewed in the DMV sys.dm_xe_sessions:
All active Extended Events sessions can be viewed in the DMV sys.dm_xe_sessions:
sys.dm_xe_sessions
SELECT * FROM sys.dm_xe_sessions;
For more information about active Extended Events DMVs, including sys.dm_xe_sessions, see Microsoft
Docs:
For more information on the set of DMVs for accessing definitions for all Extended Events sessions,
including sys.server_event_sessions, see Microsoft Docs:
Note: A session can be created without targets, in which case the session data is only visible
using Watch Live Data in SSMS.
18-8 Performance and Monitoring
Types
sys.dem_xe_objects; types
SELECT * FROM sys.dm_xe_objects
WHERE object_type = 'type';
Maps
A map is a lookup table for integer values. Internally, many event and action data values are stored as
integers; maps link these integer values to text values that are easier to interpret.
sys.dm_xe_map_values
SELECT * FROM sys.dm_xe_map_values
ORDER BY name, map_key;
Demonstration Steps
1. Start the 20762C-MIA-DC, and 20762C-MIA-SQL virtual machines, and then log on to 20762C-
MIA-SQL as ADVENTUREWORKS\Student with the password Pa55w.rd.
3. In the User Account Control dialog box, click Yes and wait for the script to finish.
4. Start SQL Server Management Studio and connect to the MIA-SQL database engine instance using
Windows authentication.
8. Select code under the comment that begins Step 1, and then click Execute to create an Extended
Events session.
9. Select code under the comment that begins Step 2, and then click Execute to verify that the session
metadata is visible.
10. Select code under the comment that begins Step 3, and then click Execute to start the session and
execute some queries.
11. Select code under the comment that begins Step 4, and then click Execute to query the session data.
12. Select code under the comment that begins Step 5, and then click Execute to refine the session data
query.
13. In Object Explorer, under MIA-SQL, expand Management, expand Extended Events, expand
Sessions, expand SqlStatementCompleted, and then double-click package0.ring_buffer.
14. In the Data column, click the XML value, and note that this is the same data that is returned by the
query under the comment that begins Step 4 (note that additional statements will have been
captured because you ran the code earlier).
15. In Object Explorer, right-click SqlStatementCompleted, and then click Watch Live Data.
16. In the Demo 1 - create xe sessions.sql query pane, select the code under the comment that begins
Step 7, and then click Execute to execute some SQL statements.
17. In the MIA-SQL - SqlStatementCompleted: Live Data pane. Wait for the events to be captured and
displayed; this can take a few seconds. Other SQL statements from background processes might be
captured by the session.
18. In the Demo 1 - create xe sessions.sql query pane, select the code under the comment that begins
Step 8, and then click Execute to stop the session.
20. In the Session Properties dialog box, review the settings on the General, Events, Data Storage, and
Advanced pages, if necessary referring back to the session definition under the comment that begins
Step 1.
22. In the Demo 1 - create xe sessions.sql query pane, select the code under the comment that begins
Step 10, and then click Execute to drop the session.
23. Keep SQL Server Management Studio open for the next demonstration.
18-10 Performance and Monitoring
Lesson 2
Working with Extended Events
This lesson discusses using Extended Events. It covers common scenarios in which you might create
Extended Events sessions for troubleshooting and performance optimization, in addition to the
system_health Extended Events session, which captures several events relevant to performance tuning.
Lesson Objectives
At the end of this lesson, you will be able to:
Configuring Sessions
As you have learned, Extended Events sessions are
composed from several other object types,
primarily events and targets. Sessions also have a
number of configuration options that are set at
session level:
o ALLOW_SINGLE_EVENT_LOSS. An event can be dropped from the session if the buffers are full. A
compromise between performance and data loss, this is the default value.
o NO_EVENT_LOSS. Events are never discarded; tasks that trigger events must wait until event
buffer space is available. Potential for severe performance impact, but no data loss.
MAX_DISPATCH_LATENCY. The amount of time events will be held in event buffers before being
dispatched to targets—defaults to 30 seconds. You may set this value to INFINITE, in which case the
buffer is only dispatched when it is full, or the session is stopped.
MAX_EVENT_SIZE. For single events larger than the size of the buffers specified by MAX_MEMORY,
use this setting. If a value is specified (in kilobytes or megabytes), it must be greater than
MAX_MEMORY.
MEMORY_PARTITION_MODE
STARTUP_STATE. When set to ON, the session will start when SQL Server starts. The default value is
OFF.
TRACK_CAUSALITY. When set to ON, an identifier is added to each event identifying the task that
triggered the event. With this, you can determine whether one event is caused by another.
For more information about configuring a session through Transact-SQL, see Microsoft Docs:
Configuring Targets
Several Extended Events targets take configuration
values when they are added to a session.
Event File
The event file target can be used to write session
data to a file. It takes the following configuration
parameters:
filename. The file name to write to; this can
be any valid file name. If a full path is not
specified, the file will be created in the
\MSSQL\Log folder of the SQL Server instance
on which the session is created.
max_file_size. The largest size that the file may grow to; the default value is 1 GB.
max_rollover_files. The number of files that have reached max_file_size to retain. The oldest file is
deleted when this number of files is reached.
increment. The file growth increment, in megabytes. The default value is twice the size of the session
buffer.
For more information on configuring the event file target, see the SQL Server Technical Documentation:
Event Pairing
The event pairing target is used to match events that occur in pairs (for example, statement starting and
statement completing, or lock acquired and lock released), and report on beginning events that have no
matching end event. It takes the following configuration parameters:
max_orphans. The maximum number of unpaired events the target will collect. The default value is
10,000. When this number is reached, events in the target are discarded on a first-in, first-out basis.
For more information on configuring the event pairing target, see the SQL Server Technical
Documentation:
The callstack, sql_text, and session_id for sessions that have waited for more than 15 seconds on
selected resources (including latches).
The callstack, sql_text, and session_id for any sessions that have waited for 30 seconds or more for
locks.
The callstack, sql_text, and session_id for any sessions that have waited for a long time for
preemptive waits. (A preemptive wait occurs when SQL Server is waiting for external API calls to
complete; the trigger time varies by wait type.)
The callstack and session_id for CLR allocation and virtual allocation failures (when insufficient
memory is available).
A ring buffer target, configured to hold up to 5,000 events and to occupy no more than 4 MB.
Note: The details of the system_health session are best understood by looking at its
definition. You can generate a definition from SSMS:
1. Connect SSMS Object Explorer to a SQL Server instance on which you have administrative rights.
2. In the Object Explorer pane, expand Management, expand Extended Events, and then expand
Sessions.
Right-click on the system_health node, click Script As, click CREATE TO, and then click New
Query Editor Window. A script to recreate the system_health session will be generated.
Because both targets are configured to roll over and discard the oldest data they contain when they are
full, the system_health session will only contain the most recent issues. On instances of SQL Server where
the system_health session is capturing many events, the targets might roll over before you can examine
specific events.
Execution Time-outs
When a Transact-SQL statement runs for longer
than the client application’s command time-out
setting, a time-out error will be raised by the client
application. Without detailed client application
logging, it may be difficult to identify the
statement causing a time-out.
Troubleshooting ASYNC_NETWORK_IO
The ASYNC_NETWORK_IO wait type occurs when the database engine is waiting for a client application to
consume a result set. This can occur because the client application processes a result set row-by-row as it
is returned from the database server.
Developing SQL Databases 18-15
To troubleshoot this issue with Extended Events, capture the sqlos.wait_info event, filtering on wait_type
value NETWORK_IO. The histogram target might be suitable for this investigation, using either the client
application name or the client host name to define histogram groups.
The sqlserver.error_reported event can be used to track errors as they are raised. The is_intercepted
column can be used to identify if an error is handled in a TRY…CATCH block.
Tracking Recompilations
Query execution plan recompilations occur when a plan in the plan cache is discarded and recompiled.
High numbers of plan recompilations might indicate a performance problem, and may cause CPU
pressure. Windows performance counters can be used to track overall recompilation counts for a SQL
Server instance, but more detail may be needed to investigate further.
Mid-page splits.
Page splits for new allocations.
Mid-page splits create fragmentation and more transaction log records due to data movement.
Tracking page splits alone using the sqlserver.page_split event is inefficient because this does not
differentiate the problematic mid-page splits and normal allocation splits. The sqlserver.transaction_log
event can be used for tracking LOP_DELETE_SPLIT operations to identify the problematic page splits. A
histogram target might be most suitable for this task, grouping either on database_id to find the
database with the most page splits, or, within a single database, on alloc_unit_id to find the indexes with
the most page splits.
18-16 Performance and Monitoring
The sqlos.wait_info event can be used to track waits across multiple concurrent sessions.
You can test for this effect by comparing the number of events returned from a ring buffer in XML with
the count of events returned in the XML document header—or check the value of the truncated attribute
in the XML header.
Reduce the size of the MAX_MEMORY setting for the ring buffer to reduce the likelihood that the
formatted data will exceed 4 MB. No single value is guaranteed to work; you may have to try a setting
and be prepared to adjust it to minimize the truncation effect while still collecting a useful volume of
data in the ring buffer.
Note: This effect is not strictly limited to the ring buffer target; it can occur on any target
that stores output in memory buffers (ring buffer target, histogram target, event pairing target,
and event counter target). However, it is most likely to affect the ring buffer target because it
stores unaggregated raw data. All the other targets using memory buffers contain aggregated
data, and are therefore less likely to exceed 4 MB when formatted.
query_post_execution_showplan. Returns the actual query execution plan when a query is executed.
When using any of these events, you should consider that adding them to a session, even when predicates
are used to limit the events captured, can have a significant impact on the performance of the database
engine instance. This effect is most marked with the query_post_execution_showplan event. You should
limit your use of these events to troubleshooting specific issues; they should not be included in an
Extended Events session that is always running.
18-18 Performance and Monitoring
Demonstration Steps
1. In SSMS, in Solution Explorer, double-click Demo 2 - track waits by session.sql.
2. In Object Explorer, expand Management, expand Extended Events, right-click Sessions, and then
click New Session.
3. In the New Session dialog box, on the General page, in the Session name box, type Waits by
Session.
4. On the Events page, in the Event library box, type wait, and then, in the list below, double-click
wait_info to add it to the Selected events list.
10. In the Type list, click event_file, in the File name on server box, type
D:\Demofiles\Mod18\waitbysession, in the first Maximum file size box, type 5, in the second
Maximum file size box, click MB, and then click OK.
11. In Object Explorer, under Sessions, right-click Waits by Session, and then click Start Session.
12. In File Explorer, in the D:\Demofiles\Mod18 folder, right-click start_load_1.ps1, and then click Run
with PowerShell. If a message is displayed asking you to confirm a change in execution policy, type
Y, and then press Enter. Leave the workload to run for a minute or so before proceeding.
13. In SSMS, in the Demo 2 - track waits by session.sql query pane, select the code under the comment
that begins Step 14, click Execute, and then review the results.
14. Select the code under the comment that begins Step 15, and then click Execute to stop and drop the
session, and to stop the workload.
15. In File Explorer, in the D:\Demofiles\Mod18 folder, note that one (or more) files with a name
matching waitbysession*.xel have been created.
17. Keep SQL Server Management Studio open for the next demonstration.
Developing SQL Databases 18-19
Categorize Activity
Categorize each Extended Events target type into the appropriate category. Indicate your answer by
writing the category number to the right of each item.
Items
3 Histogram target
Category 1 Category 2
Written to Written to
Memory File on Disk
Buffers
18-20 Performance and Monitoring
Lesson 3
Live Query Statistics
Live Query Statistics gives immediate insight into the execution of a query, making the debugging of
long-running queries easier to resolve. You can see each step of the plan exactly as it executes.
Lesson Objectives
After completing this lesson, you will be able to:
Use Live Query Statistics to view execution plans for queries as they are running.
Enabling Live Query Statistics for all sessions adds the statistics to Activity Monitor. There are two ways
that you can do this:
Execute SET STATISTICS PROFILE ON or SET STATISTICS XML ON in the target session. Both return
the same data, but SET STATISTICS XML ON returns the data as XML, enabling another application
to process the results.
Enable the query_post_execution_showplan extended event. This is a server setting that will affect
all settings.
Note: When enabling Live Query Statistics for all sessions, remember that there is a
performance overhead to running it.
Demonstration Steps
1. In SSMS, in Solution Explorer, double-click Demo 3 - live query statistics.sql script file.
2. Highlight the script under the Step 1 description, and then click Execute.
3. Highlight the script under the Step 2 description, and then click Execute.
5. Highlight the script under the Step 4 description, and then click Execute.
Lesson 4
Optimize Database File Configuration
This lesson looks at the options for configuring database files, including tempdb.
Lesson Objectives
At the end of this lesson, you will be able to:
Configure tempdb.
Understanding tempdb
tempdb is recreated each time SQL Server
starts, and is dropped when SQL Server is
stopped. Like all databases, it inherits from the
model database.
tempdb is a shared temporary database for all databases on a SQL Server instance—this means that a
single database can cause performance problems for all the databases on that instance.
tempdb is a system database. It is not a database you normally work with directly, but a temporary
storage area for objects created by users, internal objects, and version stores. These objects are
created and destroyed during normal operation. User objects include local and global temporary
tables, table variables, temporary indexes, and tables from table-valued functions.
tempdb is used to hold intermediate results by queries that include GROUP BY, ORDER BY, or UNION
clauses where intermediate results need to be stored when they can’t be cached.
tempdb holds work tables for hash join and hash aggregate operations, in addition to work tables for
cursor, spool operations, and large object (LOB) storage.
In addition, tempdb acts as a version store for online index operations, and transactions with READ
COMMITTED SNAPSHOT and SNAPSHOT isolation levels.
All the databases on an instance rely on tempdb for fast reads and writes, and most SQL Server databases
generate a great deal of tempdb activity. If tempdb runs out of space, errors will occur causing a
significant amount of disruption in a production environment.
18-24 Performance and Monitoring
Also, if there are latch contention issues, performance will suffer. A latch is a type of lock made on GAMs
(Global Allocation Maps), SGAMs (Shared Global Allocation Maps) and PFS (Page Free Space) pages. These
pages are used to determine where tempdb data can be written. If tempdb has only one data file, it is
easy to run into latch contention issues. With several data files, the load is spread between many PFS,
GAM, and SGAM pages to determine where data can be written.
Store tempdb on separate storage. You get the best performance when database data files, log files,
and tempdb files are held separately.
Store tempdb on fast storage. Use Solid State Disks (SSDs) to improve performance of tempdb data.
Best Practice: Use fast storage for tempdb. Unlike a log file that writes records to disk
sequentially, tempdb has varied reads and writes, and benefits from fast storage media.
Configuring tempdb
You can configure both tempdb data files, and log
files. The options include:
Number of files. The default value is either
eight or the number of logical processor cores
on your server. Microsoft recommends that, if
you have less than eight processors, then the
number of tempdb data files should be the
same as the number of processors. If your
server has more than eight processors, and
you experience contention issues, increase the
number of data files in multiples of four; or
make changes to the way your databases
work to reduce tempdb contention. For optimal performance, you should only have the necessary
number of tempdb data files.
Developing SQL Databases 18-25
Initial size (MB). Make all tempdb data files the same size. This is important because of the
algorithm used for page allocation. If files differ in size, you will not get the intended performance
improvements. The page size required will depend on the database workload—8 MB is the default for
primary and secondary tempdb data files.
Total initial size (MB). The total size of all tempdb data files.
Autogrowth (MB). The number of megabytes that each data file will increase by when they run out
of space. All tempdb data files will grow by the same amount, and at the same time. The
recommended, and default size, is 64 MB. You should always allow tempdb data files to grow—if they
run out of space, you will get errors instead of the intended operations.
Total autogrowth (MB). The total number of megabytes when all tempdb data files autogrow.
Data directories. You can store your tempdb data files in different directories. SQL Server supports
local disk storage, shared storage, and SMB file shares.
Log file initial size (MB). The log is used to roll back transactions. However, tempdb cannot be
backed up, and uses minimal logging—there is no point-in-time recovery with tempdb.
Log file autogrowth (MB). The default value is 64 MB. The maximum size is 2 TB. Always allow the
tempdb log file to grow.
Log directory. Path for the tempdb log file. There can only be one tempdb log file, so there is only
one directory path.
Best Practice: Ensure tempdb files are large enough for normal workload without relying
on autogrowth. For best performance, autogrowth should handle the unexpected, not the
everyday.
Performance Improvements
SQL Server performance is improved by tempdb configuration in several ways:
Allocations in tempdb all use uniform extents. This reduces blocking issues when SQL Server is heavily
loaded, and means that trace flag 1118 is not needed.
Multiple data files all grow by the same amount, at the same time. If data files are different sizes, you
don’t get the same benefit in reducing contention.
The primary filegroup has the AUTOGROW_ALL_FILES property set to ON, and this cannot be
changed.
Best Practice: When configuring a SQL Server instance for failover clustering, ensure the
directories are valid for all cluster nodes. If the tempdb directory(s)—including log directory—are
not on the failover target node, SQL Server will not fail over.
tempdb Database
https://aka.ms/Yntqsx
18-26 Performance and Monitoring
sys.dm_io_virtual_file_stats
SELECT *
FROM sys.dm_io_virtual_file_stats(database_id,file_id)
Lesson 5
Metrics
This lesson looks at gathering SQL Server metrics, including creating a baseline, using dynamic
management objects (DMOs) and Windows Performance Monitor.
Lesson Objectives
After completing this lesson, you will be able to:
Use PerfMon.
Use Dynamic Management Objects to get performance metrics.
Baselines
A baseline is the quantified normal or usual state
of a SQL Server environment. A SQL Server
baseline tells you how a system typically performs.
Benefits of having a baseline include:
You can compare baselines with the current
system state to make comparisons.
Benchmarks
A benchmark is a standard point of reference against which subsequent metrics can be compared. A
benchmark is different from a baseline. For example, the benchmark for a stored procedure execution
time might be two seconds. The baseline will give the usual or normal execution time for stored
procedures. If the execution time for the specific stored procedure is less than the baseline, then it is
considered good; otherwise, the stored procedure needs to be optimized.
18-28 Performance and Monitoring
What to Capture?
Many data points are available to be collected. Consider how you will use the data before capturing a
specific data point—how can it help you diagnose and foresee performance problems? To start with,
consider collecting the following:
System usage. System usage is described in terms of CPU, I/O, and memory consumption. You can
check these basic Performance Monitor counters against the current values, in case of sudden
performance degradation. These values can also be used to define a system usage trend, which will
help further with capacity planning.
SQL Server configurations. These are instance-level or database-level configuration settings, such as
max server memory, degree of parallelism, or auto shrink.
Database size information. The system will stop when it runs out of storage space. Capture
database and file size information to help you react proactively to space issues, thereby preventing
system downtime.
Wait statistics. Wait statistics are helpful when troubleshooting SQL Server performance issues. They
give insight into the root cause of an issue and are helpful when optimizing a slow system.
It is also necessary to have a data retention strategy. It is not advisable to keep a year or six months’ worth
of baseline data, because this data is not likely to be useful. In addition, capturing data during off-peak
hours will only add additional data to the storage without being useful.
Best Practice: Capture relevant data and keep it only for as long as it is useful—typically
three to four months.
In addition, other important DMVs that you should consider monitoring are:
Users Sessions
SQL Server uses session_ids to track users connected to SQL Server. The sys.dm_exec_session DMV collects
information about sessions including time connected, CPU usage, memory usage, and more.
For example, to display a list of users connected to SQL Server, plus the time they have been connected in
milliseconds:
sys.dm_exec_session
SELECT login_name, SUM(total_elapsed_time)/1000 AS time_connected_seconds
FROM sys.dm_exec_sessions
GROUP BY login_name;
Query Performance
Statistics play an important role in ensuring queries are executed in the most efficient way. Use the
following DMOs in combination to identify queries that have missing statistics:
Performance Monitor
Windows Performance Monitor is a snap-in for
Microsoft Management Console (MMC) that
comes with the Windows Server operating system.
Performance Monitor provides graphical views
onto the performance of the operating system and
the server. Performance Monitor is helpful because
it includes data about the server and its operating
system, in addition to SQL Server. You can view
performance data either from log files or in real
time.
Display real-time system performance data in three formats—line graph, histogram, and report.
Monitor overall system health, SQL Server health, or the health of other applications by selecting
counters from the available performance objects.
Record current performance counter values in text files and databases to analyze later. You can
analyze the performance data by using file manipulation techniques or Transact-SQL queries against
the appropriate database.
18-30 Performance and Monitoring
Create custom sets of performance counters known as a “data collector set” that you can then
schedule to run as appropriate.
Configure and respond to alerts. For example, when a specified threshold is reached, start a particular
data collector set or a particular program.
You can use Performance Monitor for real-time monitoring, and to establish a baseline for SQL Server
performance. You can collect performance data over time and analyze it to calculate workload
characteristics such as peak and off-peak hours, average CPU usage, memory usage, and more. It is often
useful to demonstrate performance gains or losses following a system change. Use Performance Monitor
to compare counter values before and after implementation.
Performance Monitor is a lightweight tool, with minimal performance overhead for sampling intervals of
greater than one second. The default or optimal sampling interval is 15 seconds. The amount of I/O that
Performance Monitor generates will depend on the number of counters, the sampling interval, and the
underlying storage. If there is an I/O issue, consider saving the performance data on separate storage and
only enable the counters that you need.
a. Monitoring Tools
c. Reports
2. In the leftmost pane, expand Monitoring Tools, and then click Performance Monitor. This will open
the Performance Monitor window in the rightmost pane.
4. When you have added the required counters, click OK to view performance information.
Developing SQL Databases 18-31
By default, Performance Monitor shows the last 100 seconds of data. This value can be changed from the
Performance Monitor properties window that is opened by right-clicking on Performance Monitor and
selecting properties.
There are three different types of graph available in Performance Monitor: Line, Histogram, and Report.
Performance Monitor provides data collector sets to automate collection of selected counters. There are
two types of data collector sets: system and user defined. The system set includes OS and network specific
counters but does not include SQL Server counters. The data collector sets can also be triggered to start
when a specific event or alert occurs. For example, a data collector set can be started when the available
memory is less than 100 MB. To set up and schedule a data collector set to collect performance counters,
follow these steps:
2. In the Performance Monitor window, in the leftmost pane, expand Data Collector Sets, right-click
User Defined, click New, and then click Data Collector Set. The Create new Data Collector Set
dialog box will appear.
3. In the Create new Data Collector Set dialog box, type a name, click Create manually, and then click
Next.
4. In the Create data logs section, select Performance counter, and then click Next.
5. Choose the appropriate performance counters.
6. Specify a sampling interval, and then click Finish. You can now schedule the data collector or execute
manually as required.
1. Right-click the data collector set you created, and then click Properties.
2. On the Schedule tab, click Add, and in the Folder Action dialog box, schedule the collection.
3. On the Stop Condition tab, specify a duration or maximum size for the set.
The data collector set will use your schedule to start collecting data or you can start it manually by using
the Action menu.
CPU Usage
Processor:
o %Processor Time
o %Privileged Time
Process (sqlservr.exe):
o %Processor Time
o %Privileged Time
The %Processor Time counter gives information about the total CPU usage and should be monitored for
each available CPU. The Process (sqlservr.exe)/% Processor Time counter details how much CPU the SQL
Server instance is using. If high CPU usage is a result of another application, you should investigate
options for tuning that application. Occasional CPU spikes may occur and should not cause concern, but
you should investigate prolonged values of greater than 80 percent.
18-32 Performance and Monitoring
Memory Usage
Memory
o Available Mbytes
o Lazy writes/sec
o Buffer cache hit ratio
o Page reads/sec
o Page writes/sec
The Memory/Available Mbytes counter shows the amount of physical memory that is immediately
available for allocation to a process or for system use. Ideally, this should be more than 300 MB. When it
drops to less than 64 MB, on most servers, Windows will display low memory notifications. The SQLOS
reacts to these notifications by reducing its memory usage.
The page life expectancy counter shows the amount of time that data pages stay in the buffer pool.
Ideally, this should be more than 300 seconds. If page life expectancy is less than 300 seconds, investigate
other buffer manager counters to get to the root cause. If the Lazy writes/sec counter is consistently non-
zero, along with low page life expectancy, and high page reads/sec and page writes/sec counters, there is
a buffer pool contention. The buffer cache hit ratio counter shows how often SQL Server gets a page from
the buffer rather than the disk. This should ideally be close to 100 percent.
The total server memory is the current amount of memory that an instance of SQL Server is using. The
target server memory is the amount of memory that is allocated to a SQL Server instance. Ideally, total
server memory is equal to target server memory on a stable system. If total server memory is less than the
target server memory, it means that SQL Server is still populating the cache and loading the data pages
into memory. A sudden decrease in total server memory indicates a problem and needs further
investigation.
Disk Usage
Physical Disk
Paging File
o %Usage
o Forwarded Records/sec
o Full Scans/sec
o Index Searches/sec
Developing SQL Databases 18-33
o Page splits/sec
The Avg. Disk sec/Read counter shows the average time taken, in seconds, to read data from disk.
Similarly, the Avg. Disk sec/Write counter shows the average time taken, in seconds, to write data to disk.
High values of these counters may not indicate hardware issues. Poorly tuned queries and missing or
unused indexes may result in high I/O usage.
The Forwarded Records/sec value should be less than 10 per 100 batch requests/sec. Consider creating a
clustered index if this counter is consistently high. A high value for the Full Scans/sec counter may cause
high CPU usage. Full scans on smaller tables are acceptable; however, a large number of scans on big
tables should be investigated. The Counter Page splits/sec value should ideally be less than 20 per 100
batch requests/sec. A high number of page splits may result in blocking, high I/O, or memory pressure.
Set an appropriate fill factor value to balance out page splits.
Batch requests/sec
SQL compilations/sec
SQL recompilations/sec
User connections
Logins/sec
Logouts/sec
The batch requests/sec value is the number of Transact-SQL batch requests that SQL Server receives per
second. The SQL compilations/sec counter shows the number of times per second that SQL compilations
have occurred. A high number of SQL compilations and recompilations may cause a CPU bottleneck. The
SQL compilations/sec value should ideally be less than 10 percent of the number of batch requests/sec;
SQL recompilations should ideally be less than 10 percent of the total number of SQL compilations/sec.
The user connections counter shows the number of users who are currently connected to a SQL Server
instance. The logins/sec and logouts/sec values should ideally be less than two. If the value is consistently
greater than two, it means that the connection pooling is not being correctly used by the application.
This is not an exhaustive list of counters to be considered, but these are good starting points when
baselining SQL Server.
18-34 Performance and Monitoring
Microsoft Excel
The performance data, in csv format, can be
analyzed manually in Excel. If the data is collected
in binary format, the binary log file can be
converted to csv format with the relog command-
line utility. The relog utility ships with Windows
and does not require a separate installation.
The following example shows a typical command to convert a binary log file to csv format by using the
relog utility:
Analyzing data in Excel can be time-consuming. The column headers need to be formatted, the
performance data requires formatting, and then aggregate columns need to be added to get the
maximum and minimum standard deviation for the counter values. This becomes even more tedious
when more than one file is to be analyzed.
Database
The performance data can be imported into SQL Server and analyzed by using Transact-SQL statements.
The performance data is imported into a database manually, loaded by using SQL Server Integration
Services, or loaded by using the relog utility. The simplest method is probably the use of the relog
command-line utility.
The following example shows the syntax to import a performance log into a database by using the relog
utility:
The relog utility accepts a binary log file and inserts it into the database that the Open Database
Connectivity (ODBC) connection specifies. The display string identifies the binary log file or the data
collector set within the database. The relog utility imports data into three different tables, as follows:
DisplayToID. This lists each data collector set that is imported into the database. A unique identifier
uniquely identifies each data collector set. The data collector is identified by the display string value
that is specified when importing the data, as shown in the preceding relog command syntax. The
table also contains the number of records that are imported and the log start and log stop time.
CounterDetails. This contains one row for each counter that is present in the performance log file.
Every counter is uniquely identified by a unique counter id. Each counter has an associated machine
name. This is helpful in identifying counter values from different computers.
Developing SQL Databases 18-35
CounterData. The CounterData table stores the actual counter values. The important columns are
GUID, counterID, counter value, and counterdatetime. The GUID columns link to the DisplayToID
GUID column. The counterID columns link to the CounterDetails counterID column. The counter value
column contains the actual counter value, and the counterdatetime column contains the time that the
value was recorded.
These three tables can be queried to get different counter values, as shown in the following example:
Counter Values
SELECT dd.DisplayString, cd.CounterDateTime,
cdt.ObjectName, cdt.CounterName,
cd.CounterValue
FROM dbo.CounterData cd
JOIN dbo.DisplayToID dd ON cd.GUID=dd.GUID
JOIN dbo.CounterDetails cdt on cd.CounterID=cdt.CounterID
WHERE did.DisplayString='SQLPerf'
ORDER BY cdt.ObjectName, cdt.CounterName,cd.RecordIndex;
The preceding query will list the counter values for the display string “SQLPerf.” To get the data from all
display strings, remove the filter on the DisplayString column in the preceding query.
You can aggregate data to form a baseline, and you can import data from multiple data collector sets
with different display strings, and then compare them to diagnose issues.
A sample query to get aggregate data from a particular display string or data collector set:
FROM dbo.CounterData cd
INNER JOIN dbo.DisplayToID did ON cd.GUID = did.GUID
INNER JOIN dbo.CounterDetails cdt ON cd.CounterID = cdt.CounterID
A sample query to display aggregate data from more than one display string:
FROM dbo.CounterData cd
INNER JOIN dbo.DisplayToID did ON cd.GUID = did.GUID
INNER JOIN dbo.CounterDetails cdt ON cd.CounterID = cdt.CounterID
GROUP BY did.DisplayString, RTRIM(cdt.ObjectName), RTRIM(cdt.CounterName)
You can use the preceding query to compare counter values from different data collectors. Query results can be
written to tables or flat files for further analysis.
Analyzing data manually is relatively straightforward and gives a lot of flexibility with the type of analysis you can
perform.
Developing SQL Databases 18-37
In this lab exercise, you will set up data collection for analyzing workloads during peak business hours,
and implement a baseline methodology to collect performance data at frequent intervals. This will enable
comparisons to be made with the baseline.
Objectives
After completing this lab, you will be able to:
Password: Pa55w.rd
3. Execute Workload
2. In the AnalyzeSQLEE session live data window, stop the feed data, and then add the duration,
query_hash, and statement columns to the view.
Set up an Extended Events session that collects performance data for a workload.
2. Execute Workload
3. Analyze Data
2. Run the waits_collectionsjob to collect statistics before and after running the RunWorkload.cmd
file multiple times.
2. Using the collected waits data, write and execute a query to find the percentage of waits. In the
D:\Labfiles\Lab18\Starter\20762 folder, the WaitBaselinePercentage.sql file has a sample
solution script.
Developing SQL Databases 18-39
3. Using the collected waits data, write and execute a query to find the top 10 waits. In the
D:\Labfiles\Lab18\Starter\20762 folder, the WaitBaselineTop10.sql file has a sample solution
script.
Results: After completing this exercise, you will have implemented a baseline for a workload.
Question: What advantages do you see in using Extended Events to monitor your SQL
Server databases?
18-40 Performance and Monitoring
Review Question(s)
Question: Do you use baselines to help you manage your SQL Server systems? If so, what
tools do you use to create baselines? If not, what are your reasons for not creating baselines?
Developing SQL Databases 18-41
Course Evaluation
Your evaluation of this course will help Microsoft understand the quality of your learning experience.
Please work with your training provider to access the course evaluation form.
Microsoft will keep your answers to this survey private and confidential and will use your responses to
improve your future learning experience. Your open and honest feedback is valuable and appreciated.