트랜잭션 잠금 및 행 버전 관리 지침Transaction Locking and Row Versioning Guide

적용 대상:Applies to: 예SQL ServerSQL Server(지원되는 모든 버전)yesSQL ServerSQL Server (all supported versions) 예Azure SQL DatabaseAzure SQL DatabaseYesAzure SQL DatabaseAzure SQL Database 예Azure SQL Managed InstanceAzure SQL Managed InstanceYesAzure SQL Managed InstanceAzure SQL Managed Instance 예Azure Synapse AnalyticsAzure Synapse AnalyticsyesAzure Synapse AnalyticsAzure Synapse Analytics 예병렬 데이터 웨어하우스Parallel Data Warehouseyes병렬 데이터 웨어하우스Parallel Data Warehouse적용 대상:Applies to: 예SQL ServerSQL Server(지원되는 모든 버전)yesSQL ServerSQL Server (all supported versions) 예Azure SQL DatabaseAzure SQL DatabaseYesAzure SQL DatabaseAzure SQL Database 예Azure SQL Managed InstanceAzure SQL Managed InstanceYesAzure SQL Managed InstanceAzure SQL Managed Instance 예Azure Synapse AnalyticsAzure Synapse AnalyticsyesAzure Synapse AnalyticsAzure Synapse Analytics 예병렬 데이터 웨어하우스Parallel Data Warehouseyes병렬 데이터 웨어하우스Parallel Data Warehouse

어느 데이터베이스에서든 트랜잭션을 제대로 관리하지 않으면 사용자가 많은 시스템에 경합 및 성능 문제가 발생할 수 있습니다.In any database, mismanagement of transactions often leads to contention and performance problems in systems that have many users. 데이터에 액세스하는 사용자 수가 늘어나면 애플리케이션에서 트랜잭션을 효율적으로 사용하는 것이 중요합니다.As the number of users that access the data increases, it becomes important to have applications that use transactions efficiently. 이 지침에서는 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 각 트랜잭션의 물리적 무결성을 유지하는 데 사용하는 잠금 및 행 버전 관리 메커니즘과 애플리케이션에서 트랜잭션을 효율적으로 제어할 수 있는 방법에 대해 설명합니다.This guide describes the locking and row versioning mechanisms the SQL Server 데이터베이스 엔진SQL Server Database Engine uses to ensure the physical integrity of each transaction and provides information on how applications can control transactions efficiently.

적용 대상: SQL ServerSQL Server(별도로 언급하지 않는 한 SQL Server 2005(9.x)SQL Server 2005 (9.x)~SQL Server 2019 (15.x)SQL Server 2019 (15.x)) 및 Azure SQL DatabaseAzure SQL DatabaseApplies to: SQL ServerSQL Server (SQL Server 2005(9.x)SQL Server 2005 (9.x) through SQL Server 2019 (15.x)SQL Server 2019 (15.x), unless noted otherwise) and Azure SQL DatabaseAzure SQL Database.

트랜잭션 기본 사항Transaction Basics

트랜잭션은 하나의 논리적 작업 단위로 수행되는 일련의 작업입니다.A transaction is a sequence of operations performed as a single logical unit of work. 작업의 논리적 단위는 ACID(원자성, 일관성, 격리성 및 영속성) 속성이라고 하는 네 가지 속성을 통해 트랜잭션으로서의 자격을 부여합니다.A logical unit of work must exhibit four properties, called the atomicity, consistency, isolation, and durability (ACID) properties, to qualify as a transaction.

원자성Atomicity
트랜잭션은 더 이상 분류할 수 없는 작업 단위여야 하며 모든 데이터 수정 작업이 수행되거나 하나도 수행되지 말아야 합니다.A transaction must be an atomic unit of work; either all of its data modifications are performed, or none of them are performed.

일관성Consistency
완료된 트랜잭션의 모든 데이터는 일관되어야 합니다.When completed, a transaction must leave all data in a consistent state. 관계형 데이터베이스에서는 트랜잭션 수정에 모든 규칙을 적용하여 모든 데이터 무결성을 유지해야 합니다.In a relational database, all rules must be applied to the transaction's modifications to maintain all data integrity. 트랜잭션 마지막에는 B-tree 인덱스 또는 이중 연결 목록 등 모든 내부적 데이터 구조를 반드시 수정해야 합니다.All internal data structures, such as B-tree indexes or doubly-linked lists, must be correct at the end of the transaction.

격리Isolation
동시 트랜잭션에 의한 수정은 다른 동시 트랜잭션에 의한 수정과 격리되어야 합니다.Modifications made by concurrent transactions must be isolated from the modifications made by any other concurrent transactions. 트랜잭션에서 다른 동시 트랜잭션이 수정하기 전 상태의 데이터를 보거나 두 번째 트랜잭션이 완료된 후의 데이터를 볼 수는 있지만 중간 상태는 볼 수 없습니다.A transaction either recognizes data in the state it was in before another concurrent transaction modified it, or it recognizes the data after the second transaction has completed, but it does not recognize an intermediate state. 결과적으로 시작 데이터를 다시 로드하고 일련의 트랜잭션을 재생하여 원래 트랜잭션이 수행된 후의 상태로 데이터를 되돌릴 수 있는데 이를 순차성이라고 합니다.This is referred to as serializability because it results in the ability to reload the starting data and replay a series of transactions to end up with the data in the same state it was in after the original transactions were performed.

영속성Durability
완전 내구성이 있는 트랜잭션이 완료되고 나면 그 영향이 영구적으로 시스템에 적용됩니다.After a fully durable transaction has completed, its effects are permanently in place in the system. 수정은 시스템에 오류가 발생한 경우에도 지속됩니다.The modifications persist even in the event of a system failure. SQL Server 2014(12.x)SQL Server 2014 (12.x) 이상에서 지연된 영구 트랜잭션을 사용할 수 있습니다.and later enable delayed durable transactions. 지연된 영구적 트랜잭션은 트랜잭션 로그 레코드가 디스크에 유지되기 전에 커밋됩니다.Delayed durable transactions commit before the transaction log record is persisted to disk. 지연된 트랜잭션 내구성에 대한 자세한 내용은 트랜잭션 내구성 항목을 참조하세요.For more information on delayed transaction durability see the topic Transaction Durability.

SQL 프로그래머는 적시에 트랜잭션을 시작하고 끝내 데이터의 논리적 일관성을 유지하는 책임을 맡고 있습니다.SQL programmers are responsible for starting and ending transactions at points that enforce the logical consistency of the data. 프로그래머는 조직의 업무 규칙과 관련하여 데이터를 일관된 상태로 유지할 수 있도록 데이터 수정 순서를 정의해야 합니다.The programmer must define the sequence of data modifications that leave the data in a consistent state relative to the organization's business rules. 그런 다음 이러한 수정 문을 하나의 트랜잭션에 포함하여 SQL Server 데이터베이스 엔진SQL Server Database Engine가 트랜잭션의 물리적 무결성을 유지할 수 있게 해야 합니다.The programmer includes these modification statements in a single transaction so that the SQL Server 데이터베이스 엔진SQL Server Database Engine can enforce the physical integrity of the transaction.

각 트랜잭션의 물리적 무결성을 유지하는 메커니즘을 제공하는 것은 SQL Server 데이터베이스 엔진SQL Server Database Engine과 같은 기업 데이터베이스 시스템의 책임입니다.It is the responsibility of an enterprise database system, such as an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine, to provide mechanisms ensuring the physical integrity of each transaction. SQL Server 데이터베이스 엔진SQL Server Database Engine은 다음을 제공합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine provides:

  • 트랜잭션 격리성을 유지하는 잠금 기능Locking facilities that preserve transaction isolation.

  • 로깅 기능은 트랜잭션 내구성을 유지합니다.Logging facilities ensure transaction durability. 완전 내구성 있는 트랜잭션의 경우 트랜잭션이 커밋되기 전에 로그 레코드가 디스크에 확정됩니다.For fully durable transactions the log record is hardened to disk before the transactions commits. 따라서 서버 하드웨어, 운영 체제 또는 SQL Server 데이터베이스 엔진SQL Server Database Engine의 인스턴스 자체에 오류가 발생하더라도, 인스턴스는 다시 시작될 때 트랜잭션 로그를 사용하여 불완전한 트랜잭션을 자동으로 시스템 오류 시점으로 롤백합니다.Thus, even if the server hardware, operating system, or the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine itself fails, the instance uses the transaction logs upon restart to automatically roll back any incomplete transactions to the point of the system failure. 지연된 영구적 트랜잭션은 트랜잭션 로그 레코드가 디스크에 유지되기 전에 커밋됩니다.Delayed durable transactions commit before the transaction log record is hardened to disk. 이러한 트랜잭션은 로그 레코드가 디스크에 확정되기 전에 시스템 오류가 발생하면 손실될 수 있습니다.Such transactions may be lost if there is a system failure before the log record is hardened to disk. 지연된 트랜잭션 내구성에 대한 자세한 내용은 트랜잭션 내구성 항목을 참조하세요.For more information on delayed transaction durability see the topic Transaction Durability.

  • 트랜잭션 원자성 및 일관성을 유지하는 트랜잭션 관리 기능.Transaction management features that enforce transaction atomicity and consistency. 트랜잭션이 일단 시작된 후에는 성공적으로 완료(커밋)되어야 합니다. 그렇지 않으면 SQL Server 데이터베이스 엔진SQL Server Database Engine이 트랜잭션 시작 이후 만들어진 모든 데이터 수정 내용을 실행 취소합니다.After a transaction has started, it must be successfully completed (committed), or the SQL Server 데이터베이스 엔진SQL Server Database Engine undoes all of the data modifications made since the transaction started. 이 작업은 변경 전의 상태를 데이터에 반환하기 때문에 트랜잭션 롤백이라고도 합니다.This operation is referred to as rolling back a transaction because it returns the data to the state it was prior to those changes.

트랜잭션 제어Controlling Transactions

애플리케이션은 주로 트랜잭션 시작 및 종료 시기를 지정하여 트랜잭션을 제어합니다.Applications control transactions mainly by specifying when a transaction starts and ends. 트랜잭션 시작 및 종료 시기는 Transact-SQLTransact-SQL 문 또는 데이터베이스 API(응용 프로그래밍 인터페이스) 함수를 사용하여 지정할 수 있습니다.This can be specified by using either Transact-SQLTransact-SQL statements or database application programming interface (API) functions. 시스템은 트랜잭션을 불완전하게 종료하는 오류를 올바르게 처리할 수도 있어야 합니다.The system must also be able to correctly handle errors that terminate a transaction before it completes. 자세한 내용은 트랜잭션, ODBC의 트랜잭션OLEDB(SQL Server Native Client)의 트랜잭션을 참조하세요.For more information, see Transactions, Transactions in ODBC and Transactions in SQL Server Native Client (OLEDB).

기본적으로 트랜잭션은 연결 수준에서 관리됩니다.By default, transactions are managed at the connection level. 한 연결에서 트랜잭션이 시작되면 트랜잭션이 끝날 때까지 해당 연결에서 실행되는 모든 Transact-SQLTransact-SQL 문은 트랜잭션의 일부가 됩니다.When a transaction is started on a connection, all Transact-SQLTransact-SQL statements executed on that connection are part of the transaction until the transaction ends. 그러나 MARS(Multiple Active Result Set) 세션에서는 Transact-SQLTransact-SQL 명시적 또는 암시적 트랜잭션이 일괄 처리 수준에서 관리되는 일괄 처리 범위의 트랜잭션이 됩니다.However, under a multiple active result set (MARS) session, a Transact-SQLTransact-SQL explicit or implicit transaction becomes a batch-scoped transaction that is managed at the batch level. 일괄 처리가 완료될 때 일괄 처리 범위의 트랜잭션이 커밋되거나 롤백되지 않으면 SQL ServerSQL Server에서 해당 트랜잭션을 자동으로 롤백합니다.When the batch completes, if the batch-scoped transaction is not committed or rolled back, it is automatically rolled back by SQL ServerSQL Server. 자세한 내용은 MARS(Multiple Active Result Sets) 사용을 참조하세요.For more information, see Using Multiple Active Result Sets (MARS).

트랜잭션 시작Starting Transactions

API 함수와 Transact-SQLTransact-SQL 문을 사용하여 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스에서 명시적, 자동 커밋 또는 암시적 트랜잭션을 시작할 수 있습니다.Using API functions and Transact-SQLTransact-SQL statements, you can start transactions in an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine as explicit, autocommit, or implicit transactions.

명시적 트랜잭션Explicit Transactions
명시적 트랜잭션은 API 함수를 통해 또는 Transact-SQLTransact-SQL BEGIN TRANSACTION, COMMIT TRANSACTION, COMMIT WORK, ROLLBACK TRANSACTION 또는 ROLLBACK WORK Transact-SQLTransact-SQL 문을 실행하여 트랜잭션 시작 및 완료를 모두 명시적으로 정의하는 트랜잭션입니다.An explicit transaction is one in which you explicitly define both the start and end of the transaction through an API function or by issuing the Transact-SQLTransact-SQL BEGIN TRANSACTION, COMMIT TRANSACTION, COMMIT WORK, ROLLBACK TRANSACTION, or ROLLBACK WORK Transact-SQLTransact-SQL statements. 트랜잭션이 끝나면 명시적 트랜잭션이 시작된 시기의 트랜잭션 모드인 암시적 모드나 자동 커밋 모드로 되돌려집니다.When the transaction ends, the connection returns to the transaction mode it was in before the explicit transaction was started, either implicit or autocommit mode.

명시적 트랜잭션에서는 다음 문을 제외한 모든 Transact-SQLTransact-SQL 문을 사용할 수 있습니다.You can use all Transact-SQLTransact-SQL statements in an explicit transaction, except for the following statements:

ALTER DATABASEALTER DATABASE

CREATE DATABASECREATE DATABASE

DROP FULLTEXT INDEXDROP FULLTEXT INDEX

ALTER FULLTEXT CATALOGALTER FULLTEXT CATALOG

CREATE FULLTEXT CATALOGCREATE FULLTEXT CATALOG

RECONFIGURERECONFIGURE

ALTER FULLTEXT INDEXALTER FULLTEXT INDEX

CREATE FULLTEXT INDEXCREATE FULLTEXT INDEX

RESTORERESTORE

BACKUPBACKUP

DROP DATABASEDROP DATABASE

전체 텍스트 시스템 저장 프로시저Full-text system stored procedures

CREATE DATABASECREATE DATABASE

DROP FULLTEXT CATALOGDROP FULLTEXT CATALOG

데이터베이스 옵션을 설정하는 sp_dboption 또는 명시적/암시적 트랜잭션 내에서 master 데이터베이스를 수정하는 시스템 프로시저sp_dboption to set database options or any system procedure that modifies the master database inside explicit or implicit transactions.

참고

UPDATE STATISTICS는 명시적 트랜잭션 내에서 사용할 수 있습니다.UPDATE STATISTICS can be used inside an explicit transaction. 그러나 UPDATE STATISTICS는 포함하는 트랜잭션과 별개로 커밋하며 롤백할 수 없습니다.However, UPDATE STATISTICS commits independently of the enclosing transaction and cannot be rolled back.

자동 커밋 트랜잭션Autocommit Transactions
자동 커밋 모드는 SQL Server 데이터베이스 엔진SQL Server Database Engine의 기본 트랜잭션 관리 모드입니다.Autocommit mode is the default transaction management mode of the SQL Server 데이터베이스 엔진SQL Server Database Engine. 모든 Transact-SQLTransact-SQL 문은 완료 시 커밋되거나 롤백됩니다.Every Transact-SQLTransact-SQL statement is committed or rolled back when it completes. 문이 성공적으로 완료되면 커밋되며 오류가 발생하면 롤백됩니다.If a statement completes successfully, it is committed; if it encounters any error, it is rolled back. SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스 연결은 명시적 트랜잭션이나 암시적 트랜잭션에 의해 이 기본 모드가 무시되지 않는 한 자동 커밋 모드로 작동합니다.A connection to an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine operates in autocommit mode whenever this default mode has not been overridden by either explicit or implicit transactions. 자동 커밋 모드는 또한 ADO, OLE DB, ODBC 및 DB-Library의 기본 모드이기도 합니다.Autocommit mode is also the default mode for ADO, OLE DB, ODBC, and DB-Library.

암시적 트랜잭션Implicit Transactions
연결이 암시적 트랜잭션 모드에서 작동할 때는 현재 트랜잭션이 커밋 또는 롤백된 후 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스에서 자동으로 새 트랜잭션을 시작합니다.When a connection is operating in implicit transaction mode, the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine automatically starts a new transaction after the current transaction is committed or rolled back. 트랜잭션 시작을 직접 지정할 필요 없이 각 트랜잭션을 커밋 또는 롤백하기만 하면 됩니다.You do nothing to delineate the start of a transaction; you only commit or roll back each transaction. 암시적 트랜잭션 모드는 트랜잭션의 연속 체인을 생성합니다.Implicit transaction mode generates a continuous chain of transactions. API 함수나 Transact-SQLTransact-SQL SET IMPLICIT_TRANSACTIONS ON 문을 통해 암시적 트랜잭션 모드를 설정합니다.Set implicit transaction mode on through either an API function or the Transact-SQLTransact-SQL SET IMPLICIT_TRANSACTIONS ON statement. 이 모드를 자동 커밋 OFF라고 하며 JDBC의 setAutoCommit 메서드를 참조하세요.This mode is also known as Autocommit OFF, see setAutoCommit Method in JDBC

연결에 대해 암시적 트랜잭션 모드를 설정하고 나면 이러한 문을 처음 실행할 때 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스가 자동으로 트랜잭션을 시작합니다.After implicit transaction mode has been set on for a connection, the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine automatically starts a transaction when it first executes any of these statements:

ALTER TABLEALTER TABLE

FETCHFETCH

REVOKEREVOKE

CREATECREATE

GRANTGRANT

SELECTSELECT

DeleteDELETE

INSERTINSERT

TRUNCATE TABLETRUNCATE TABLE

DROPDROP

OPENOPEN

UPDATEUPDATE

  • 일괄 처리 범위의 트랜잭션Batch-scoped Transactions
    MARS(Multiple Active Result Sets)에만 해당되며, MARS 세션에서 시작되는 Transact-SQLTransact-SQL 명시적 또는 암시적 트랜잭션이 일괄 처리 범위 트랜잭션이 됩니다.Applicable only to multiple active result sets (MARS), a Transact-SQLTransact-SQL explicit or implicit transaction that starts under a MARS session becomes a batch-scoped transaction. 일괄 처리가 완료될 때 커밋되거나 롤백되지 않은 일괄 처리 범위의 트랜잭션은 SQL ServerSQL Server에서 자동으로 롤백합니다.A batch-scoped transaction that is not committed or rolled back when a batch completes is automatically rolled back by SQL ServerSQL Server.

  • 분산 트랜잭션Distributed Transactions
    분산 트랜잭션은 리소스 관리자라고 하는 둘 이상의 서버에 분산됩니다.Distributed transactions span two or more servers known as resource managers. 트랜잭션 관리는 트랜잭션 관리자라고 하는 서버 구성 요소에 의해 리소스 관리자 간에 조정되어야 합니다.The management of the transaction must be coordinated between the resource managers by a server component called a transaction manager. MS DTC(SQL Server 데이터베이스 엔진SQL Server Database EngineMicrosoftMicrosoft Distributed Transaction Coordinator) 등의 트랜잭션 관리자 또는 분산 트랜잭션 처리용 Open Group XA 사양을 지원하는 기타 트랜잭션 관리자에 의해 조정되는 분산 트랜잭션에서 리소스 관리자 역할을 합니다.Each instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine can operate as a resource manager in distributed transactions coordinated by transaction managers, such as MicrosoftMicrosoft Distributed Transaction Coordinator (MS DTC), or other transaction managers that support the Open Group XA specification for distributed transaction processing. 자세한 내용은 MS DTC 설명서를 참조하십시오.For more information, see the MS DTC documentation.

    둘 이상의 데이터베이스에 분산된 SQL Server 데이터베이스 엔진SQL Server Database Engine의 단일 인스턴스 내에 있는 트랜잭션은 실제로 분산 트랜잭션입니다.A transaction within a single instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine that spans two or more databases is actually a distributed transaction. 인스턴스는 분산 트랜잭션을 내부적으로 관리하므로 사용자에게는 로컬 트랜잭션처럼 작동합니다.The instance manages the distributed transaction internally; to the user, it operates as a local transaction.

    애플리케이션에서의 분산 트랜잭션 관리 방법은 로컬 트랜잭션과 많은 부분이 동일합니다.At the application, a distributed transaction is managed much the same as a local transaction. 트랜잭션이 끝나면 애플리케이션이 트랜잭션을 커밋 또는 롤백하도록 요청합니다.At the end of the transaction, the application requests the transaction to be either committed or rolled back. 트랜잭션 관리자는 분산 커밋을 다른 방법으로 관리하여 일부 리소스 관리자는 성공적으로 커밋하고 일부는 트랜잭션을 롤백하는 네트워크 오류의 발생 가능성을 최소화해야 합니다.A distributed commit must be managed differently by the transaction manager to minimize the risk that a network failure may result in some resource managers successfully committing while others roll back the transaction. 이렇게 하려면 커밋 프로세스를 준비 단계와 커밋 단계로 관리해야 하는데 이러한 방법을 2단계 커밋(2PC)이라고 합니다.This is achieved by managing the commit process in two phases (the prepare phase and the commit phase), which is known as a two-phase commit (2PC).

    • 준비 단계Prepare phase
      트랜잭션 관리자가 커밋 요청을 수신하면 트랜잭션과 관련된 모든 리소스 관리자에게 준비 명령을 보냅니다.When the transaction manager receives a commit request, it sends a prepare command to all of the resource managers involved in the transaction. 그런 다음 각 리소스 관리자는 트랜잭션을 지속적으로 만들고 트랜잭션에 대한 로그 이미지를 갖고 있는 버퍼를 디스크로 플러시하는 데 필요한 모든 작업을 수행합니다.Each resource manager then does everything required to make the transaction durable, and all buffers holding log images for the transaction are flushed to disk. 각 리소스 관리자가 준비 단계를 완료하면 준비 성공 또는 실패 여부를 트랜잭션 관리자에게 반환합니다.As each resource manager completes the prepare phase, it returns success or failure of the prepare to the transaction manager. SQL Server 2014(12.x)SQL Server 2014 (12.x)에서 지연된 트랜잭션 내구성이 도입되었습니다.introduced delayed transaction durability. 지연된 영구적 트랜잭션은 트랜잭션 로그 이미지가 디스크에 플러시되기 전에 커밋됩니다.Delayed durable transactions commit before log images for the transaction are flushed to disk. 지연된 트랜잭션 내구성에 대한 자세한 내용은 트랜잭션 내구성 항목을 참조하세요.For more information on delayed transaction durability see the topic Transaction Durability.

    • 커밋 단계Commit phase
      트랜잭션 관리자가 모든 리소스 관리자로부터 준비 성공 알림을 받으면 각 리소스 관리자에게 커밋 명령을 보냅니다.If the transaction manager receives successful prepares from all of the resource managers, it sends commit commands to each resource manager. 그런 다음에는 리소스 관리자가 커밋을 완료할 수 있습니다.The resource managers can then complete the commit. 모든 리소스 관리자가 성공적인 커밋을 보고하면 트랜잭션 관리자가 애플리케이션에 성공을 알립니다.If all of the resource managers report a successful commit, the transaction manager then sends a success notification to the application. 준비 실패를 보고한 리소스 관리자가 있으면 트랜잭션 관리자가 각 리소스 관리자에게 롤백 명령을 보내서 애플리케이션에게 커밋 실패를 알립니다.If any resource manager reported a failure to prepare, the transaction manager sends a rollback command to each resource manager and indicates the failure of the commit to the application.

      SQL Server 데이터베이스 엔진SQL Server Database Engine 애플리케이션은 Transact-SQLTransact-SQL 또는 데이터베이스 API를 통해 분산 트랜잭션을 관리할 수 있습니다.applications can manage distributed transactions either through Transact-SQLTransact-SQL or the database API. 자세한 내용은 BEGIN DISTRIBUTED TRANSACTION(Transact-SQL)를 참조하세요.For more information, see BEGIN DISTRIBUTED TRANSACTION (Transact-SQL).

트랜잭션 종료Ending Transactions

COMMIT 또는 ROLLBACK 문을 사용하거나 해당 API 함수를 통해 트랜잭션을 종료할 수 있습니다.You can end transactions with either a COMMIT or ROLLBACK statement, or through a corresponding API function.

  • COMMITCOMMIT
    트랜잭션이 성공하면 커밋합니다.If a transaction is successful, commit it. COMMIT 문을 사용하면 모든 트랜잭션 수정이 영구적으로 데이터베이스의 일부로 적용됩니다.A COMMIT statement guarantees all of the transaction's modifications are made a permanent part of the database. COMMIT은 또한 트랜잭션에 사용된 잠금과 같은 리소스를 해제합니다.A COMMIT also frees resources, such as locks, used by the transaction.

  • ROLLBACKROLLBACK
    트랜잭션에서 오류가 발생하거나 사용자가 트랜잭션을 취소하려고 결정한 경우 트랜잭션을 롤백합니다.If an error occurs in a transaction, or if the user decides to cancel the transaction, then roll the transaction back. ROLLBACK 문은 데이터를 트랜잭션이 시작되기 전 상태로 되돌려서 트랜잭션 진행 중 수정된 모든 내용을 취소합니다.A ROLLBACK statement backs out all modifications made in the transaction by returning the data to the state it was in at the start of the transaction. ROLLBACK은 또한 트랜잭션에서 보유 중인 리소스를 해제합니다.A ROLLBACK also frees resources held by the transaction.

참고

MARS를 지원하도록 설정된 연결에서는 실행 보류 중인 요청이 있을 경우 API 함수를 통해 시작한 명시적 트랜잭션을 커밋할 수 없습니다.Under connections enabled to support multiple active result sets (MARS), an explicit transaction started through an API function cannot be committed while there are pending requests for execution. 보류 중인 작업이 있는 동안 이러한 유형의 트랜잭션을 커밋하려고 하면 오류가 발생합니다.Any attempt to commit this type of transaction while there are outstanding operations running will result in an error.

트랜잭션 처리 중 오류Errors During Transaction Processing

오류로 인해 트랜잭션이 성공적으로 완료되지 않은 경우 SQL ServerSQL Server에서는 자동으로 트랜잭션을 롤백하고 해당 트랜잭션에 보유 중인 모든 리소스를 해제합니다.If an error prevents the successful completion of a transaction, SQL ServerSQL Server automatically rolls back the transaction and frees all resources held by the transaction. 클라이언트와 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스 간의 네트워크 연결이 끊어진 경우 네트워크에서 이 인스턴스에게 연결이 끊어진 것을 알릴 때 해당 연결에서 보류 중인 트랜잭션은 모두 롤백됩니다.If the client's network connection to an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine is broken, any outstanding transactions for the connection are rolled back when the network notifies the instance of the break. 클라이언트 애플리케이션에 오류가 발생하거나 클라이언트 컴퓨터가 다운 또는 다시 시작되는 경우에도 네트워크 연결은 끊어지고 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스는 네트워크에서 연결이 끊어진 것을 확인하면 보류 중인 트랜잭션을 모두 롤백합니다.If the client application fails or if the client computer goes down or is restarted, this also breaks the connection, and the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine rolls back any outstanding connections when the network notifies it of the break. 클라이언트가 애플리케이션에서 로그오프하면 보류 중인 트랜잭션은 모두 롤백됩니다.If the client logs off the application, any outstanding transactions are rolled back.

일괄 처리에서 제약 조건 위반 등 런타임 문 오류가 발생하면 SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 기본적으로 오류를 발생시킨 문만 롤백합니다.If a run-time statement error (such as a constraint violation) occurs in a batch, the default behavior in the SQL Server 데이터베이스 엔진SQL Server Database Engine is to roll back only the statement that generated the error. 이 동작은 SET XACT_ABORT 문을 사용하여 변경할 수 있습니다.You can change this behavior using the SET XACT_ABORT statement. SET XACT_ABORT ON이 실행된 후에는 모든 런타임 문 오류 발생 시 자동으로 현재 트랜잭션이 롤백됩니다.After SET XACT_ABORT ON is executed, any run-time statement error causes an automatic rollback of the current transaction. 구문 오류와 같은 컴파일 오류는 SET XACT_ABORT 옵션 설정으로 영향을 받지 않습니다.Compile errors, such as syntax errors, are not affected by SET XACT_ABORT. 자세한 내용은 SET XACT_ABORT(Transact-SQL)를 참조하세요.For more information, see SET XACT_ABORT (Transact-SQL).

오류가 발생하면 수정 동작(COMMIT 또는 ROLLBACK)을 애플리케이션 코드에 포함해야 합니다.When errors occur, corrective action (COMMIT or ROLLBACK) should be included in application code. 트랜잭션 오류를 포함하여 오류를 효과적으로 처리할 수 있는 도구로는 Transact-SQLTransact-SQL TRY...CATCH 구문이 있습니다.One effective tool for handling errors, including those in transactions, is the Transact-SQLTransact-SQL TRY...CATCH construct. 트랜잭션이 포함된 예를 보려면 TRY...CATCH(Transact-SQL)를 참조하십시오.For more information with examples that include transactions, see TRY...CATCH (Transact-SQL). SQL Server 2012(11.x)SQL Server 2012 (11.x)부터 THROW 문을 사용하여 예외를 발생시키고 실행 영역을 TRY...CATCH 구문의 CATCH 블록으로 넘길 수 있습니다.Beginning with SQL Server 2012(11.x)SQL Server 2012 (11.x), you can use the THROW statement to raise an exception and transfers execution to a CATCH block of a TRY...CATCH construct. 자세한 내용은 THROW(Transact-SQL)을 참조하세요.For more information, see THROW (Transact-SQL).

자동 커밋 모드에서 컴파일 오류 및 런타임 오류Compile and Run-time Errors in Autocommit mode

자동 커밋 모드에서는 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스가 한 SQL 문이 아니라 전체 일괄 처리를 롤백하는 것처럼 보일 때가 있습니다.In autocommit mode, it sometimes appears as if an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine has rolled back an entire batch instead of just one SQL statement. 이러한 상황은 런타임 오류가 아니라 컴파일 오류가 발생했을 때 나타납니다.This happens if the error encountered is a compile error, not a run-time error. 컴파일 오류가 발생하면 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 실행 계획을 작성할 수 없으므로 일괄 처리가 실행되지 않습니다.A compile error prevents the SQL Server 데이터베이스 엔진SQL Server Database Engine from building an execution plan, so nothing in the batch is executed. 오류를 생성한 문 이전의 모든 문이 롤백되는 것처럼 보이지만 오류가 발생하면 일괄 처리의 모든 문이 실행되지 않습니다.Although it appears that all of the statements before the one generating the error were rolled back, the error prevented anything in the batch from being executed. 다음 예에서는 컴파일 오류가 발생하여 세 번째 일괄 처리의 INSERT 문이 하나도 실행되지 않습니다.In the following example, none of the INSERT statements in the third batch are executed because of a compile error. 처음 두 INSERT 문이 롤백되는 것처럼 보이지만 전혀 실행되지 않은 것입니다.It appears that the first two INSERT statements are rolled back when they are never executed.

CREATE TABLE TestBatch (Cola INT PRIMARY KEY, Colb CHAR(3));  
GO  
INSERT INTO TestBatch VALUES (1, 'aaa');  
INSERT INTO TestBatch VALUES (2, 'bbb');  
INSERT INTO TestBatch VALUSE (3, 'ccc');  -- Syntax error.  
GO  
SELECT * FROM TestBatch;  -- Returns no rows.  
GO  

다음 예에서는 세 번째 INSERT 문에서 런타임 기본 키 중복 오류가 발생합니다.In the following example, the third INSERT statement generates a run-time duplicate primary key error. 처음 두 INSERT 문은 성공하고 커밋되므로 런타임 오류 이후에도 유지됩니다.The first two INSERT statements are successful and committed, so they remain after the run-time error.

CREATE TABLE TestBatch (Cola INT PRIMARY KEY, Colb CHAR(3));  
GO  
INSERT INTO TestBatch VALUES (1, 'aaa');  
INSERT INTO TestBatch VALUES (2, 'bbb');  
INSERT INTO TestBatch VALUES (1, 'ccc');  -- Duplicate key error.  
GO  
SELECT * FROM TestBatch;  -- Returns rows 1 and 2.  
GO  

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 실행 시간까지 개체 이름이 확인되지 않는 지연된 이름 확인 기능을 사용합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses deferred name resolution, in which object names are not resolved until execution time. 다음 예에서는 처음 두 INSERT 문이 실행되어 커밋되므로 세 번째 TestBatch 문이 존재하지 않는 테이블을 참조하여 런타임 오류를 생성한 후에도 처음 두 행은 INSERT 테이블에 유지됩니다.In the following example, the first two INSERT statements are executed and committed, and those two rows remain in the TestBatch table after the third INSERT statement generates a run-time error by referring to a table that does not exist.

CREATE TABLE TestBatch (Cola INT PRIMARY KEY, Colb CHAR(3));  
GO  
INSERT INTO TestBatch VALUES (1, 'aaa');  
INSERT INTO TestBatch VALUES (2, 'bbb');  
INSERT INTO TestBch VALUES (3, 'ccc');  -- Table name error.  
GO  
SELECT * FROM TestBatch;  -- Returns rows 1 and 2.  
GO  

잠금 및 행 버전 관리 기본 사항Locking and Row Versioning Basics

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 여러 사용자가 동시에 데이터를 액세스하는 경우 다음 메커니즘을 사용하여 트랜잭션의 무결성을 확인하고 데이터베이스의 일관성을 유지합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses the following mechanisms to ensure the integrity of transactions and maintain the consistency of databases when multiple users are accessing data at the same time:

  • 잠금Locking

    각 트랜잭션은 해당 트랜잭션이 종속되는 행, 페이지 또는 테이블 등의 리소스에 대해 서로 다른 유형의 잠금을 요청합니다.Each transaction requests locks of different types on the resources, such as rows, pages, or tables, on which the transaction is dependent. 잠금은 다른 트랜잭션의 리소스 수정을 차단하여 잠금을 요청하는 트랜잭션에 문제가 발생하지 않도록 합니다.The locks block other transactions from modifying the resources in a way that would cause problems for the transaction requesting the lock. 각 트랜잭션은 잠긴 리소스에 더 이상 종속되지 않게 되면 잠금을 해제합니다.Each transaction frees its locks when it no longer has a dependency on the locked resources.

  • 행 버전 관리Row versioning

    행 버전 관리 기반 격리 수준을 사용하면 SQL Server 데이터베이스 엔진SQL Server Database Engine은 수정된 각 행의 버전을 유지 관리합니다.When a row versioning-based isolation level is enabled, the SQL Server 데이터베이스 엔진SQL Server Database Engine maintains versions of each row that is modified. 애플리케이션에서는 잠금을 사용하여 모든 읽기 작업을 보호하는 대신 트랜잭션이 해당 트랜잭션 또는 쿼리 시작 부분에 있는 행 버전을 사용하여 데이터를 확인하도록 지정할 수 있습니다.Applications can specify that a transaction use the row versions to view data as it existed at the start of the transaction or query instead of protecting all reads with locks. 행 버전 관리를 사용하면 읽기 작업에 의해 다른 트랜잭션이 차단될 가능성이 크게 줄어듭니다.By using row versioning, the chance that a read operation will block other transactions is greatly reduced.

잠금 및 행 버전 관리는 사용자가 커밋되지 않은 데이터를 읽을 수 없도록 하고 여러 사용자가 동일한 데이터를 동시에 변경하지 못하도록 합니다.Locking and row versioning prevent users from reading uncommitted data and prevent multiple users from attempting to change the same data at the same time. 잠금 또는 행 버전 관리를 사용하지 않는 경우 데이터에 대해 쿼리를 실행하면 아직 데이터베이스에서 커밋되지 않은 데이터가 반환되어 예기치 않은 결과가 나타날 수 있습니다.Without locking or row versioning, queries executed against that data could produce unexpected results by returning data that has not yet been committed in the database.

애플리케이션에서는 다른 트랜잭션에 의해 수정되지 않도록 트랜잭션을 보호하는 수준을 정의하는 트랜잭션 격리 수준을 선택할 수 있습니다.Applications can choose transaction isolation levels, which define the level of protection for the transaction from modifications made by other transactions. 개별 Transact-SQLTransact-SQL 문에 대해 테이블 수준 힌트를 지정하여 애플리케이션의 요구 사항에 맞는 동작을 더 적절하게 설정할 수 있습니다.Table-level hints can be specified for individual Transact-SQLTransact-SQL statements to further tailor behavior to fit the requirements of the application.

동시 데이터 액세스 관리Managing Concurrent Data Access

특정 리소스에 여러 사용자가 동시에 액세스하는 것을 동시 액세스라고 합니다.Users who access a resource at the same time are said to be accessing the resource concurrently. 동시 데이터 액세스를 위해서는 다른 사용자가 현재 사용하고 있는 리소스를 여러 사용자가 수정하려 할 때 역효과가 발생하지 않도록 하는 메커니즘이 필요합니다.Concurrent data access requires mechanisms to prevent adverse effects when multiple users try to modify resources that other users are actively using.

동시성 효과Concurrency Effects

사용자가 데이터를 수정하면 동시에 같은 데이터를 읽거나 수정 중인 다른 사용자에게 영향을 미칠 수 있습니다.Users modifying data can affect other users who are reading or modifying the same data at the same time. 이러한 사용자들을 가리켜 데이터에 동시에 액세스한 사용자라고 합니다.These users are said to be accessing the data concurrently. 데이터 스토리지 시스템에 동시성 제어가 없으면 사용자가 다음과 같은 부작용을 겪을 수 있습니다.If a data storage system has no concurrency control, users could see the following side effects:

  • 업데이트 손실Lost updates

    업데이트 손실은 둘 이상의 트랜잭션이 같은 행을 선택한 다음 원래 선택한 값을 기준으로 행을 업데이트할 때 발생합니다.Lost updates occur when two or more transactions select the same row and then update the row based on the value originally selected. 이때 각 트랜잭션은 다른 트랜잭션을 인식하지 못합니다.Each transaction is unaware of the other transactions. 마지막 업데이트가 다른 트랜잭션의 업데이트를 덮어쓰므로 데이터가 손실됩니다.The last update overwrites updates made by the other transactions, which results in lost data.

    예를 들어 두 명의 편집자가 같은 문서를 복사한다고 가정합니다.For example, two editors make an electronic copy of the same document. 각 편집자가 각자 복사본을 변경한 다음 변경된 복사본을 저장하면 원본 문서를 덮어쓰게 됩니다.Each editor changes the copy independently and then saves the changed copy thereby overwriting the original document. 변경된 복사본을 마지막으로 저장한 편집자가 다른 편집자의 변경 내용을 덮어씁니다.The editor who saves the changed copy last overwrites the changes made by the other editor. 한 편집자가 트랜잭션을 마치고 커밋할 때까지 다른 편집자가 파일에 액세스할 수 없도록 하면 이 문제를 해결할 수 있습니다.This problem could be avoided if one editor could not access the file until the other editor had finished and committed the transaction.

  • 커밋되지 않은 종속성(더티 읽기)Uncommitted dependency (dirty read)

    커밋되지 않은 종속성은 다른 트랜잭션이 업데이트 중인 행을 두 번째 트랜잭션이 선택할 때 발생합니다.Uncommitted dependency occurs when a second transaction selects a row that is being updated by another transaction. 두 번째 트랜잭션이 읽고 있는 데이터는 아직 커밋되지 않았지만 현재 행을 업데이트 중인 트랜잭션에 의해 변경될 수 있습니다.The second transaction is reading data that has not been committed yet and may be changed by the transaction updating the row.

    예를 들어 한 편집자가 문서를 변경 중이라고 가정합니다.For example, an editor is making changes to an electronic document. 변경하는 동안 다른 편집자가 그 시점까지 변경된 내용이 모두 포함된 문서를 복사한 다음 문서를 배포합니다.During the changes, a second editor takes a copy of the document that includes all the changes made so far, and distributes the document to the intended audience. 그런데 첫 번째 편집자가 그때까지 변경한 내용이 잘못되었다고 판단하여 편집 내용을 지우고 문서를 저장합니다.The first editor then decides the changes made so far are wrong and removes the edits and saves the document. 이 경우 배포된 문서에는 더 이상 존재하지 않으며 무시해야 하는 내용이 포함되어 있습니다.The distributed document contains edits that no longer exist and should be treated as if they never existed. 첫 번째 편집자가 수정 내용을 최종 저장하고 트랜잭션 커밋할 때까지 아무도 변경된 문서를 읽을 수 없도록 하면 이 문제를 해결할 수 있습니다.This problem could be avoided if no one could read the changed document until the first editor does the final save of modifications and commits the transaction.

  • 일관성 없는 분석(반복하지 않는 읽기)Inconsistent analysis (nonrepeatable read)

    일관성 없는 분석은 두 번째 트랜잭션이 같은 행에 여러 번 액세스하며 이때마다 다른 데이터를 읽을 경우 발생합니다.Inconsistent analysis occurs when a second transaction accesses the same row several times and reads different data each time. 일관성 없는 분석은 두 번째 트랜잭션이 읽고 있는 데이터를 다른 트랜잭션이 변경하고 있다는 점에서 커밋되지 않은 종속성과 비슷합니다.Inconsistent analysis is similar to uncommitted dependency in that another transaction is changing the data that a second transaction is reading. 그러나 일관성 없는 분석의 경우 두 번째 트랜잭션이 읽은 데이터는 내용을 변경한 트랜잭션에 의해 커밋된 것입니다.However, in inconsistent analysis, the data read by the second transaction was committed by the transaction that made the change. 또한 같은 행을 여러 번 읽어야 하고 매번 정보가 다른 트랜잭션에 의해 변경됩니다. 이를 반복하지 않는 읽기라고 합니다.Also, inconsistent analysis involves multiple reads (two or more) of the same row, and each time the information is changed by another transaction; thus, the term nonrepeatable read.

    예를 들어 한 편집자가 같은 문서를 두 번 읽는 동안 그 사이에 작성자가 문서를 다시 작성할 수 있습니다.For example, an editor reads the same document twice, but between each reading the writer rewrites the document. 그러면 편집자가 같은 문서를 두 번째 읽을 때 문서가 변경되어 있습니다.When the editor reads the document for the second time, it has changed. 원래의 읽기는 반복되지 않습니다.The original read was not repeatable. 편집자가 마지막으로 문서 읽기를 마칠 때까지 작성자가 문서를 변경하지 못하게 하면 이 문제를 해결할 수 있습니다.This problem could be avoided if the writer could not change the document until the editor has finished reading it for the last time.

  • 가상 읽기Phantom reads

    가상 읽기는 두 개의 동일한 쿼리가 실행되고 두 번째 쿼리에서 반환된 행 컬렉션이 다른 경우 발생하는 상황입니다.A phantom read is a situation that occurs when two identical queries are executed and the collection of rows returned by the second query is different. 아래의 예에서는 이러한 상황이 발생하는 경우를 보여 줍니다.The example below shows how this may occur. 아래의 두 트랜잭션이 동시에 실행되고 있다고 가정합니다.Assume the two transactions below are executing at the same time. 두 번째 트랜잭션의 SELECT 문이 두 트랜잭션에서 사용하는 데이터를 변경하기 때문에 첫 번째 트랜잭션의 두 INSERT 문에서 서로 다른 결과를 반환할 수 있습니다.The two SELECT statements in the first transaction may return different results because the INSERT statement in the second transaction changes the data used by both.

    --Transaction 1  
    BEGIN TRAN;  
    SELECT ID FROM dbo.employee  
    WHERE ID > 5 and ID < 10;  
    --The INSERT statement from the second transaction occurs here.  
    SELECT ID FROM dbo.employee  
    WHERE ID > 5 and ID < 10;  
    COMMIT;  
    
    --Transaction 2  
    BEGIN TRAN;  
    INSERT INTO dbo.employee  
      (Id, Name) VALUES(6 ,'New');  
    COMMIT;   
    
  • 행 업데이트로 인한 읽기 누락 및 두 번 읽기Missing and double reads caused by row updates

    • 업데이트된 행이 누락되거나 업데이트된 행이 여러 번 표시됨Missing an updated row or seeing an updated row multiple times

      READ UNCOMMITTED 수준에서 실행되는 트랜잭션은 현재 트랜잭션에서 읽은 데이터를 다른 트랜잭션에서 수정하지 못하도록 하는 공유 잠금을 실행하지 않습니다.Transactions that are running at the READ UNCOMMITTED level do not issue shared locks to prevent other transactions from modifying data read by the current transaction. READ COMMITTED 수준에서 실행되는 트랜잭션은 공유 잠금을 실행하지만 행을 읽은 후에는 행 또는 페이지 잠금을 해제합니다.Transactions that are running at the READ COMMITTED level do issue shared locks, but the row or page locks are released after the row is read. 어떤 경우든 인덱스를 검색할 때 사용자가 읽기 작업을 수행하는 동안 다른 사용자가 행의 인덱스 키 열을 변경하면 키 변경으로 인해 사용자가 아직 검색하지 않은 위치로 행이 이동될 경우 해당 행이 다시 나타날 수 있습니다.In either case, when you are scanning an index, if another user changes the index key column of the row during your read, the row might appear again if the key change moved the row to a position ahead of your scan. 마찬가지로 키 변경으로 인해 사용자가 이미 읽은 인덱스 위치로 행이 이동될 경우 해당 행이 나타나지 않을 수 있습니다.Similarly, the row might not appear if the key change moved the row to a position in the index that you had already read. 이 문제를 방지하려면 SERIALIZABLE 또는 HOLDLOCK 힌트 또는 행 버전 관리를 사용합니다.To avoid this, use the SERIALIZABLE or HOLDLOCK hint, or row versioning. 자세한 내용은 테이블 힌트(Transact-SQL)를 참조하세요.For more information, see Table Hints (Transact-SQL).

    • 업데이트 대상이 아니었던 하나 이상의 행이 누락됨Missing one or more rows that were not the target of update

      READ UNCOMMITTED을 사용할 때 사용자 쿼리에서 할당 순서 검색(IAM 페이지 사용)을 사용하여 행을 읽는 경우 다른 트랜잭션에 의해 페이지 분할이 발생하면 행이 누락될 수 있습니다.When you are using READ UNCOMMITTED, if your query reads rows using an allocation order scan (using IAM pages), you might miss rows if another transaction is causing a page split. 페이지 분할 중에 테이블 잠금이 유지되므로 커밋된 읽기를 사용할 때는 누락이 발생하지 않습니다. 또한 업데이트로 인해 페이지 분할이 발생하지 않으므로 테이블에 클러스터형 인덱스가 없는 경우 누락이 발생하지 않습니다.This cannot occur when you are using read committed because a table lock is held during a page split and does not happen if the table does not have a clustered index, because updates do not cause page splits.

동시성 유형Types of Concurrency

여러 사용자가 동시에 데이터베이스의 데이터를 수정할 수 있도록 하려면 특정 사용자의 수정 내용이 다른 사용자의 수정 내용에 영향을 주지 않도록 제어 시스템을 구현해야 합니다.When many people attempt to modify data in a database at the same time, a system of controls must be implemented so that modifications made by one person do not adversely affect those of another person. 이것을 동시성 제어라고 합니다.This is called concurrency control.

동시성 제어는 동시성 제어 구현 방법에 따라 두 가지로 분류됩니다.Concurrency control theory has two classifications for the methods of instituting concurrency control:

  • 비관적 동시성 제어Pessimistic concurrency control

    다른 사용자에게 영향을 주는 데이터 수정은 수행할 수 없도록 하는 잠금 방식입니다.A system of locks prevents users from modifying data in a way that affects other users. 한 사용자가 잠금을 유발하는 동작을 수행하면 다른 사용자는 이 소유자가 잠금을 해제할 때까지 해당 잠금과 충돌하는 동작을 수행할 수 없습니다.After a user performs an action that causes a lock to be applied, other users cannot perform actions that would conflict with the lock until the owner releases it. 이러한 방식은 동시성 충돌이 발생하는 경우 잠금을 사용하여 데이터를 보호하는 비용이 트랜잭션을 롤백하는 비용보다 작고 데이터에 대한 경합이 치열한 환경에 주로 사용되기 때문에 비관적 제어라고 합니다.This is called pessimistic control because it is mainly used in environments where there is high contention for data, where the cost of protecting data with locks is less than the cost of rolling back transactions if concurrency conflicts occur.

  • 낙관적 동시성 제어Optimistic concurrency control

    낙관적 동시성 제어에서는 사용자가 데이터를 읽을 때 해당 데이터를 잠그지 않습니다.In optimistic concurrency control, users do not lock data when they read it. 사용자가 데이터를 업데이트할 때는 다른 사용자가 해당 데이터를 읽은 후 변경하지 않았는지 검사가 진행됩니다.When a user updates data, the system checks to see if another user changed the data after it was read. 다른 사용자가 데이터를 업데이트한 경우에는 오류가 발생합니다.If another user updated the data, an error is raised. 일반적으로 오류를 수신한 사용자의 트랜잭션이 롤백되고 다시 시작됩니다.Typically, the user receiving the error rolls back the transaction and starts over. 이러한 방식은 가끔씩 트랜잭션을 롤백하는 비용이 데이터를 읽을 때 잠그는 비용보다 작고 데이터에 대한 경합이 낮은 환경에 주로 사용되기 때문에 낙관적 제어라고 합니다.This is called optimistic because it is mainly used in environments where there is low contention for data, and where the cost of occasionally rolling back a transaction is lower than the cost of locking data when read.

SQL ServerSQL Server에서는 다양한 동시성 제어 유형을 지원합니다.supports a range of concurrency control. 사용자는 연결에 대한 트랜잭션 격리 수준 또는 커서에 대한 동시성 옵션을 선택하여 동시성 제어 유형을 지정하게 됩니다.Users specify the type of concurrency control by selecting transaction isolation levels for connections or concurrency options on cursors. 이러한 특성은 Transact-SQLTransact-SQL 문을 사용하거나 ADO, ADO.NET, OLE DB 및 ODBC 등의 데이터베이스 API(응용 프로그래밍 인터페이스) 속성과 특성을 통해 정의할 수 있습니다.These attributes can be defined using Transact-SQLTransact-SQL statements, or through the properties and attributes of database application programming interfaces (APIs) such as ADO, ADO.NET, OLE DB, and ODBC.

SQL Server 데이터베이스 엔진SQL Server Database Engine의 격리 수준Isolation Levels in the SQL Server 데이터베이스 엔진SQL Server Database Engine

한 트랜잭션을 리소스 또는 다른 트랜잭션에서 수정한 데이터 내용으로부터 격리하는 정도를 정의하는 격리 수준을 트랜잭션에 지정할 수 있습니다.Transactions specify an isolation level that defines the degree to which one transaction must be isolated from resource or data modifications made by other transactions. 격리 수준은 허용되는 동시성 부작용(예: 커밋되지 않은 읽기 또는 가상 읽기)의 관점에서 설명됩니다.Isolation levels are described in terms of which concurrency side-effects, such as dirty reads or phantom reads, are allowed.

트랜잭션 격리 수준으로 제어할 수 있는 사항은 다음과 같습니다.Transaction isolation levels control:

  • 데이터를 읽을 때 잠금을 확보할지 여부 및 요청되는 잠금의 종류Whether locks are taken when data is read, and what type of locks are requested.
  • 읽기 잠금의 보유 기간How long the read locks are held.
  • 읽기 작업이 다른 트랜잭션에서 수정한 행을 참조할 경우 선택할 수 있는 다음과 같은 옵션Whether a read operation referencing rows modified by another transaction:
    • 행에 대한 배타적 잠금이 해제될 때까지 차단Blocks until the exclusive lock on the row is freed.
    • 문 또는 트랜잭션 시작 당시 커밋된 행 버전 검색Retrieves the committed version of the row that existed at the time the statement or transaction started.
    • 커밋되지 않은 데이터 수정 내용 읽기Reads the uncommitted data modification.

중요

트랜잭션 격리 수준을 선택해도 데이터 수정 내용을 보호하기 위해 획득된 잠금에는 영향을 주지 않습니다.Choosing a transaction isolation level does not affect the locks acquired to protect data modifications. 설정된 격리 수준에 관계없이 트랜잭션은 항상 수정하는 데이터에 대해 배타적 잠금을 얻고 해당 트랜잭션이 완료될 때까지 이 잠금을 보유합니다.A transaction always gets an exclusive lock on any data it modifies, and holds that lock until the transaction completes, regardless of the isolation level set for that transaction. 읽기 작업의 경우 트랜잭션 격리 수준은 대개 다른 트랜잭션에서 수정한 내용의 영향을 받지 않도록 보호 수준을 정의합니다.For read operations, transaction isolation levels primarily define the level of protection from the effects of modifications made by other transactions.

격리 수준이 낮을수록 동시에 데이터를 액세스할 수 있는 사용자가 많아지지만 동시성 부작용(예: 커밋되지 않은 읽기 또는 업데이트 손실) 횟수도 늘어납니다.A lower isolation level increases the ability of many users to access data at the same time, but increases the number of concurrency effects (such as dirty reads or lost updates) users might encounter. 반대로 격리 수준이 높을수록 동시성 부작용 종류가 줄어들지만 시스템 리소스가 더 많이 필요하게 되고 한 트랜잭션이 다른 트랜잭션을 차단하게 될 확률도 높아집니다.Conversely, a higher isolation level reduces the types of concurrency effects that users may encounter, but requires more system resources and increases the chances that one transaction will block another. 적절한 격리 수준을 선택하려면 애플리케이션의 데이터 무결성 요구 사항과 각 격리 수준에 의해 야기되는 오버헤드를 신중하게 평가해야 합니다.Choosing the appropriate isolation level depends on balancing the data integrity requirements of the application against the overhead of each isolation level. 최상위 격리 수준인 직렬화 가능의 경우 트랜잭션이 읽기 작업을 반복할 때마다 정확히 동일한 데이터를 검색하지만 다중 사용자 시스템에서 다른 사용자에게 영향을 줄 수 있는 수준의 잠금을 수행함으로써 이를 달성합니다.The highest isolation level, serializable, guarantees that a transaction will retrieve exactly the same data every time it repeats a read operation, but it does this by performing a level of locking that is likely to impact other users in multi-user systems. 최하위 격리 수준인 커밋되지 않은 읽기의 경우 다른 트랜잭션에서 수정했지만 커밋되지 않은 데이터를 검색할 수 있습니다.The lowest isolation level, read uncommitted, may retrieve data that has been modified but not committed by other transactions. 커밋되지 않은 읽기에서는 모든 동시성 부작용이 발생할 수 있지만 읽기 잠금이나 버전 관리가 수행되지 않으므로 오버헤드가 최소화됩니다.All of the concurrency side effects can happen in read uncommitted, but there is no read locking or versioning, so overhead is minimized.

데이터베이스 엔진 격리 수준Database Engine Isolation Levels

ISO 표준은 다음 격리 수준을 정의합니다. 이 격리 수준은 모두 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 지원됩니다.The ISO standard defines the following isolation levels, all of which are supported by the SQL Server 데이터베이스 엔진SQL Server Database Engine:

격리 수준Isolation Level 정의Definition
READ UNCOMMITTEDRead uncommitted 물리적으로 손상된 데이터만 읽지 않도록 트랜잭션을 격리하는 최하위 격리 수준입니다.The lowest isolation level where transactions are isolated only enough to ensure that physically corrupt data is not read. 이 수준에서는 더티 읽기가 허용되므로 한 트랜잭션에서 변경한 아직 커밋되지 않은 내용을 다른 트랜잭션에서 볼 수 있습니다.In this level, dirty reads are allowed, so one transaction may see not-yet-committed changes made by other transactions.
READ COMMITTEDRead committed 트랜잭션에서는 처음 트랜잭션이 완료될 때까지 기다리지 않고 다른 트랜잭션에서 이전에 읽은 수정되지 않은 데이터를 읽을 수 있습니다.Allows a transaction to read data previously read (not modified) by another transaction without waiting for the first transaction to complete. SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 트랜잭션이 끝날 때까지 쓰기 잠금이 유지되지만(일부 데이터에서 적용됨) 읽기 잠금은 SELECT 작업이 수행되는 즉시 해제됩니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine keeps write locks (acquired on selected data) until the end of the transaction, but read locks are released as soon as the SELECT operation is performed. 이 값은 SQL Server 데이터베이스 엔진SQL Server Database Engine 기본 수준입니다.This is the SQL Server 데이터베이스 엔진SQL Server Database Engine default level.
REPEATABLE READRepeatable read SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 트랜잭션이 끝날 때까지 일부 데이터에서 획득되는 읽기 잠금 및 쓰기 잠금이 유지됩니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine keeps read and write locks that are acquired on selected data until the end of the transaction. 그러나 범위 잠금이 관리되지 않으므로 가상 읽기가 발생할 수 있습니다.However, because range-locks are not managed, phantom reads can occur.
직렬화 가능Serializable 트랜잭션이 서로 완전히 격리되는 최상위 수준입니다.The highest level where transactions are completely isolated from one another. SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 일부 데이터에서 획득되는 읽기 잠금 및 쓰기 잠금이 유지되고 트랜잭션이 끝날 때 해제됩니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine keeps read and write locks acquired on selected data to be released at the end of the transaction. 범위 잠금은 SELECT 작업에서 특히 가상 읽기를 방지하기 위해 범위가 지정된 WHERE 절을 사용할 때 필요합니다.Range-locks are acquired when a SELECT operation uses a ranged WHERE clause, especially to avoid phantom reads.

참고: 직렬화 가능 격리 수준이 요청된 경우 복제된 테이블에 대한 DDL 작업 및 트랜잭션이 실패할 수 있는데Note: DDL operations and transactions on replicated tables may fail when serializable isolation level is requested. 이는 복제 쿼리가 직렬화 가능 격리 수준과 호환되지 않을 수 있는 힌트를 사용하기 때문입니다.This is because replication queries use hints that may be incompatible with serializable isolation level.

SQL ServerSQL Server에서는 행 버전 관리를 사용하는 두 개의 추가 트랜잭션 격리 수준을 지원합니다.also supports two additional transaction isolation levels that use row versioning. 하나는 커밋된 읽기 격리를 구현한 것이고 다른 하나는 트랜잭션 격리 수준인 스냅샷입니다.One is an implementation of read committed isolation, and one is a transaction isolation level, snapshot.

행 버전 관리 기반 격리Row Versioning Isolation Level 정의Definition
커밋된 스냅샷 읽기(RCSI)Read Committed Snapshot (RCSI) READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 ON으로 설정하면 커밋된 읽기 격리가 행 버전 관리를 통해 문 수준의 읽기 일관성을 제공합니다.When the READ_COMMITTED_SNAPSHOT database option is set ON, read committed isolation uses row versioning to provide statement-level read consistency. 읽기 작업에 SCH-S 테이블 수준 잠금만 필요하고 페이지 또는 행 잠금은 필요하지 않습니다.Read operations require only SCH-S table level locks and no page or row locks. 즉, SQL Server 데이터베이스 엔진SQL Server Database Engine은 행 버전 관리를 사용하여 문 시작 시와 트랜잭션별로 데이터의 일관성이 유지된 스냅샷을 각 문에 제공합니다.That is, the SQL Server 데이터베이스 엔진SQL Server Database Engine uses row versioning to present each statement with a transactionally consistent snapshot of the data as it existed at the start of the statement. 다른 트랜잭션에 의한 데이터 업데이트 차단을 위해 잠금이 사용되지는 않습니다.Locks are not used to protect the data from updates by other transactions. 사용자 정의 함수는 UDF를 포함하는 구문 시간이 시작된 후에 커밋된 데이터를 반환할 수 있습니다.A user-defined function can return data that was committed after the time the statement containing the UDF began.

READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 기본값인 OFF로 설정하면 커밋된 격리 읽기는 공유 잠금을 사용하여 현재 트랜잭션이 읽기 작업을 실행하는 동안 다른 트랜잭션이 행을 수정하지 못하도록 합니다.When the READ_COMMITTED_SNAPSHOT database option is set OFF, which is the default setting, read committed isolation uses shared locks to prevent other transactions from modifying rows while the current transaction is running a read operation. 또한 공유 잠금은 다른 트랜잭션이 완료될 때까지 해당 트랜잭션이 수정한 행을 문이 읽을 수 없도록 합니다.The shared locks also block the statement from reading rows modified by other transactions until the other transaction is completed. 두 구현 모두 커밋된 읽기 격리에 대한 ISO 정의를 충족합니다.Both implementations meet the ISO definition of read committed isolation.
스냅샷Snapshot 스냅샷 격리 수준은 행 버전 관리를 통해 트랜잭션 수준의 읽기 일관성을 제공합니다.The snapshot isolation level uses row versioning to provide transaction-level read consistency. 읽기 작업에 SCH-S 테이블 잠금만 필요하고 페이지 또는 행 잠금은 필요하지 않습니다.Read operations acquire no page or row locks; only SCH-S table locks are acquired. 다른 트랜잭션에서 수정한 행을 읽을 때 트랜잭션 시작 당시의 행 버전을 검색합니다.When reading rows modified by another transaction, they retrieve the version of the row that existed when the transaction started. ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정하면 데이터베이스에 대해 스냅샷 격리만 사용할 수 있습니다.You can only use Snapshot isolation against a database when the ALLOW_SNAPSHOT_ISOLATION database option is set ON. 기본적으로 사용자 데이터베이스에 대해서는 이 옵션이 OFF로 설정되어 있습니다.By default, this option is set OFF for user databases.

참고: SQL ServerSQL Server에서는 메타데이터의 버전 관리를 지원하지 않습니다.Note: SQL ServerSQL Server does not support versioning of metadata. 따라서 스냅샷 격리에서 실행하는 명시적 트랜잭션에서 수행할 수 있는 DDL 작업에 대한 제한 사항이 있습니다.For this reason, there are restrictions on what DDL operations can be performed in an explicit transaction that is running under snapshot isolation. ALTER TABLE, CREATE INDEX, CREATE XML INDEX, ALTER INDEX, DROP INDEX, DBCC REINDEX, ALTER PARTITION FUNCTION, ALTER PARTITION SCHEME 또는 CLR(공용 언어 런타임) DDL 문과 같은 DDL 문은 BEGIN TRANSACTION 문 다음에 스냅샷 격리에서 허용되지 않습니다.The following DDL statements are not permitted under snapshot isolation after a BEGIN TRANSACTION statement: ALTER TABLE, CREATE INDEX, CREATE XML INDEX, ALTER INDEX, DROP INDEX, DBCC REINDEX, ALTER PARTITION FUNCTION, ALTER PARTITION SCHEME, or any common language runtime (CLR) DDL statement. 다음 명령문은 암시적 트랜잭션 내에서 스냅샷 격리를 사용하는 경우 허용됩니다.These statements are permitted when you are using snapshot isolation within implicit transactions. 기본적으로 암시적 트랜잭션은 DDL 문에서도 스냅샷 격리의 의미 체계를 적용할 수 있게 하는 단일 문입니다.An implicit transaction, by definition, is a single statement that makes it possible to enforce the semantics of snapshot isolation, even with DDL statements. 이 원칙을 위반하면 오류 3961이 발생할 수 있습니다. Snapshot isolation transaction failed in database '%.*ls' because the object accessed by the statement has been modified by a DDL statement in another concurrent transaction since the start of this transaction. It is not allowed because the metadata is not versioned. A concurrent update to metadata could lead to inconsistency if mixed with snapshot isolation.Violations of this principle can cause error 3961: Snapshot isolation transaction failed in database '%.*ls' because the object accessed by the statement has been modified by a DDL statement in another concurrent transaction since the start of this transaction. It is not allowed because the metadata is not versioned. A concurrent update to metadata could lead to inconsistency if mixed with snapshot isolation.

다음 표에서는 각 격리 수준에서 사용되는 동시성 부작용을 보여 줍니다.The following table shows the concurrency side effects enabled by the different isolation levels.

격리 수준Isolation level 커밋되지 않은 읽기Dirty read 반복되지 않는 읽기Nonrepeatable read 가상Phantom
READ UNCOMMITTEDRead uncommitted Yes Yes Yes
READ COMMITTEDRead committed No Yes Yes
REPEATABLE READRepeatable read No 아니요No Yes
스냅샷Snapshot No No No
직렬화 가능Serializable No No No

각 트랜잭션 격리 수준에서 제어하는 특정 종류의 잠금 또는 행 버전 관리에 대한 자세한 내용은 SET TRANSACTION ISOLATION LEVEL(Transact-SQL)을 참조하십시오.For more information about the specific types of locking or row versioning controlled by each transaction isolation level, see SET TRANSACTION ISOLATION LEVEL (Transact-SQL).

트랜잭션 격리 수준은 Transact-SQLTransact-SQL이나 데이터베이스 API를 통해 설정할 수 있습니다.Transaction isolation levels can be set using Transact-SQLTransact-SQL or through a database API.

Transact-SQLTransact-SQL
Transact-SQLTransact-SQL 스크립트는 SET TRANSACTION ISOLATION LEVEL 문을 사용합니다.scripts use the SET TRANSACTION ISOLATION LEVEL statement.

ADOADO
ADO 애플리케이션은 Connection 개체의 IsolationLevel 속성을 adXactReadUncommitted, adXactReadCommitted, adXactRepeatableRead 또는 adXactReadSerializable로 설정합니다.ADO applications set the IsolationLevel property of the Connection object to adXactReadUncommitted, adXactReadCommitted, adXactRepeatableRead, or adXactReadSerializable.

ADO.NETADO.NET
System.Data.SqlClient 관리 네임스페이스를 사용하는 ADO.NET 애플리케이션은 SqlConnection.BeginTransaction 메서드를 호출하고 IsolationLevel 옵션을 Unspecified, Chaos, ReadUncommitted, ReadCommitted, RepeatableRead, Serializable 및 Snapshot으로 설정할 수 있습니다.ADO.NET applications using the System.Data.SqlClient managed namespace can call the SqlConnection.BeginTransaction method and set the IsolationLevel option to Unspecified, Chaos, ReadUncommitted, ReadCommitted, RepeatableRead, Serializable, and Snapshot.

OLE DBOLE DB
OLE DB를 사용하는 애플리케이션은 트랜잭션을 시작할 때 isoLevel 을 ISOLATIONLEVEL_READUNCOMMITTED, ISOLATIONLEVEL_READCOMMITTED, ISOLATIONLEVEL_REPEATABLEREAD, ISOLATIONLEVEL_SNAPSHOT 또는 ISOLATIONLEVEL_SERIALIZABLE로 설정하고 ITransactionLocal::StartTransaction을 호출합니다.When starting a transaction, applications using OLE DB call ITransactionLocal::StartTransaction with isoLevel set to ISOLATIONLEVEL_READUNCOMMITTED, ISOLATIONLEVEL_READCOMMITTED, ISOLATIONLEVEL_REPEATABLEREAD, ISOLATIONLEVEL_SNAPSHOT, or ISOLATIONLEVEL_SERIALIZABLE.

OLE DB 애플리케이션은 자동 커밋 모드로 트랜잭션 격리 수준을 지정할 때 DBPROPSET_SESSION 속성인 DBPROP_SESS_AUTOCOMMITISOLEVELS를 DBPROPVAL_TI_CHAOS, DBPROPVAL_TI_READUNCOMMITTED, DBPROPVAL_TI_BROWSE, DBPROPVAL_TI_CURSORSTABILITY, DBPROPVAL_TI_READCOMMITTED, DBPROPVAL_TI_REPEATABLEREAD, DBPROPVAL_TI_SERIALIZABLE, DBPROPVAL_TI_ISOLATED 또는 DBPROPVAL_TI_SNAPSHOT으로 설정할 수 있습니다.When specifying the transaction isolation level in autocommit mode, OLE DB applications can set the DBPROPSET_SESSION property DBPROP_SESS_AUTOCOMMITISOLEVELS to DBPROPVAL_TI_CHAOS, DBPROPVAL_TI_READUNCOMMITTED, DBPROPVAL_TI_BROWSE, DBPROPVAL_TI_CURSORSTABILITY, DBPROPVAL_TI_READCOMMITTED, DBPROPVAL_TI_REPEATABLEREAD, DBPROPVAL_TI_SERIALIZABLE, DBPROPVAL_TI_ISOLATED, or DBPROPVAL_TI_SNAPSHOT.

ODBCODBC
ODBC 애플리케이션은 Attribute 를 SQL_ATTR_TXN_ISOLATION으로 설정하고 ValuePtr 을 SQL_TXN_READ_UNCOMMITTED, SQL_TXN_READ_COMMITTED, SQL_TXN_REPEATABLE_READ 또는 SQL_TXN_SERIALIZABLE로 설정하고 SQLSetConnectAttr을 호출합니다.ODBC applications call SQLSetConnectAttr with Attribute set to SQL_ATTR_TXN_ISOLATION and ValuePtr set to SQL_TXN_READ_UNCOMMITTED, SQL_TXN_READ_COMMITTED, SQL_TXN_REPEATABLE_READ, or SQL_TXN_SERIALIZABLE.

스냅샷 트랜잭션의 경우 애플리케이션은 Attribute를 SQL_COPT_SS_TXN_ISOLATION으로, ValuePtr을 SQL_TXN_SS_SNAPSHOT으로 설정하고 SQLSetConnectAttr을 호출합니다.For snapshot transactions, applications call SQLSetConnectAttr with Attribute set to SQL_COPT_SS_TXN_ISOLATION and ValuePtr set to SQL_TXN_SS_SNAPSHOT. SQL_COPT_SS_TXN_ISOLATION이나 SQL_ATTR_TXN_ISOLATION을 사용하여 스냅샷 트랜잭션을 검색할 수 있습니다.A snapshot transaction can be retrieved using either SQL_COPT_SS_TXN_ISOLATION or SQL_ATTR_TXN_ISOLATION.

데이터베이스 엔진에서의 잠금Locking in the Database Engine

잠금은 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 사용하는 메커니즘으로 동시에 여러 사용자가 동일한 데이터에 액세스하는 것을 동기화합니다.Locking is a mechanism used by the SQL Server 데이터베이스 엔진SQL Server Database Engine to synchronize access by multiple users to the same piece of data at the same time.

특정 트랜잭션이 데이터 읽기나 수정 등을 통해 현재 데이터 상태에 종속되기 전에 동일한 데이터를 수정하는 다른 트랜잭션의 영향을 받지 못하도록 해당 트랜잭션을 보호해야 합니다.Before a transaction acquires a dependency on the current state of a piece of data, such as by reading or modifying the data, it must protect itself from the effects of another transaction modifying the same data. 트랜잭션은 데이터에 대한 잠금을 요청하여 자체 트랜잭션을 보호합니다.The transaction does this by requesting a lock on the piece of data. 잠금에는 공유나 배타 등의 다양한 모드가 있습니다.Locks have different modes, such as shared or exclusive. 잠금 모드는 데이터에 대한 트랜잭션의 종속성 수준을 정의합니다.The lock mode defines the level of dependency the transaction has on the data. 해당 데이터에 대해 이미 다른 트랜잭션에 허용된 잠금 모드와 충돌되는 잠금은 이 트랜잭션에 허용될 수 없습니다.No transaction can be granted a lock that would conflict with the mode of a lock already granted on that data to another transaction. 특정 트랜잭션에서 이미 허용된 잠금과 충돌되는 잠금 모드를 동일한 데이터에 요청하면 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스는 첫 번째 잠금이 해제될 때까지 요청한 트랜잭션을 일시 중지합니다.If a transaction requests a lock mode that conflicts with a lock that has already been granted on the same data, the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine will pause the requesting transaction until the first lock is released.

트랜잭션을 통해 데이터를 수정하는 경우 해당 트랜잭션이 끝날 때까지 잠금을 지속하여 수정한 내용이 유지되도록 보호합니다.When a transaction modifies a piece of data, it holds the lock protecting the modification until the end of the transaction. 읽기 작업을 보호할 수 있도록 획득한 잠금을 트랜잭션에서 지속하는 기간은 트랜잭션 격리 수준 설정에 따라 다릅니다.How long a transaction holds the locks acquired to protect read operations depends on the transaction isolation level setting. 트랜잭션을 통해 지속되는 모든 잠금은 트랜잭션이 완료되어 커밋되거나 롤백될 때 해제됩니다.All locks held by a transaction are released when the transaction completes (either commits or rolls back).

일반적으로 애플리케이션은 잠금을 직접 요청하지 않습니다.Applications do not typically request locks directly. 잠금은 잠금 관리자라고 하는 SQL Server 데이터베이스 엔진SQL Server Database Engine의 일부를 통해 내부적으로 관리됩니다.Locks are managed internally by a part of the SQL Server 데이터베이스 엔진SQL Server Database Engine called the lock manager. SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스가 Transact-SQLTransact-SQL 문을 처리할 때 SQL Server 데이터베이스 엔진SQL Server Database Engine 쿼리 프로세서는 액세스할 리소스를 확인합니다.When an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine processes a Transact-SQLTransact-SQL statement, the SQL Server 데이터베이스 엔진SQL Server Database Engine query processor determines which resources are to be accessed. 쿼리 프로세서는 액세스 유형과 트랜잭션 격리 수준 설정에 따라 각 리소스를 보호하는 데 필요한 잠금 유형을 결정합니다.The query processor determines what types of locks are required to protect each resource based on the type of access and the transaction isolation level setting. 그런 다음 쿼리 프로세서는 잠금 관리자에게 적절한 잠금을 요청합니다.The query processor then requests the appropriate locks from the lock manager. 잠금 관리자는 다른 트랜잭션에서 지속되는 잠금과 충돌되지 않는 잠금을 허용합니다.The lock manager grants the locks if there are no conflicting locks held by other transactions.

잠금 세분성 및 계층Lock Granularity and Hierarchies

SQL Server 데이터베이스 엔진SQL Server Database Engine은 한 트랜잭션으로 여러 유형의 리소스를 잠글 수 있는 다양한 세분성의 잠금을 제공합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine has multigranular locking that allows different types of resources to be locked by a transaction. 잠금 비용을 최소화하기 위해 SQL Server 데이터베이스 엔진SQL Server Database Engine은 자동으로 태스크에 맞는 수준에서 리소스를 잠급니다.To minimize the cost of locking, the SQL Server 데이터베이스 엔진SQL Server Database Engine 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. 유지 관리할 잠금 수가 적으므로 오버헤드가 줄어듭니다.However, it has a lower overhead because fewer locks are being maintained.

SQL Server 데이터베이스 엔진SQL Server Database Engine이 리소스를 완전히 보호하기 위해 여러 수준의 세분성에서 잠금을 획득해야 하는 경우가 많습니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine often has to acquire locks at multiple levels of granularity to fully protect a resource. 이러한 여러 수준의 세분성 잠금 그룹을 잠금 계층 구조라고 합니다.This group of locks at multiple levels of granularity is called a lock hierarchy. 예를 들어 인덱스 읽기를 완전히 보호하기 위해 SQL Server 데이터베이스 엔진SQL Server Database Engine의 인스턴스에서는 행에 대한 공유 잠금과 페이지와 테이블에 대한 내재된 공유 잠금을 획득해야 합니다.For example, to fully protect a read of an index, an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine may have to acquire share locks on rows and intent share locks on the pages and table.

다음 표에서는 SQL Server 데이터베이스 엔진SQL Server Database Engine이 잠글 수 있는 리소스를 보여 줍니다.The following table shows the resources that the SQL Server 데이터베이스 엔진SQL Server Database Engine can lock.

리소스Resource DescriptionDescription
RIDRID 행 식별자는 힙 내의 단일 행을 잠그는 데 사용됩니다.A row identifier used to lock a single row within a heap.
KEYKEY 인덱스 내의 행 잠금은 직렬화 가능한 트랜잭션에서 키 범위를 보호하는 데 사용됩니다.A row lock within an index used to protect key ranges in serializable transactions.
PAGEPAGE 데이터 또는 인덱스 페이지와 같은 데이터베이스의 8KB 페이지입니다.An 8-kilobyte (KB) page in a database, such as data or index pages.
EXTENTEXTENT 데이터 또는 인덱스 페이지와 같은 인접한 8개의 페이지 그룹입니다.A contiguous group of eight pages, such as data or index pages.
HoBTHoBT 힙 또는 B-트리입니다.A heap or B-tree. 클러스터형 인덱스가 없는 테이블에서 힙 데이터 페이지나 B-트리(인덱스)를 보호하는 잠금입니다.A lock protecting a B-tree (index) or the heap data pages in a table that does not have a clustered index.
TABLETABLE 모든 데이터와 인덱스가 포함된 전체 테이블입니다.The entire table, including all data and indexes.
FILEFILE 데이터베이스 파일입니다.A database file.
APPLICATIONAPPLICATION 애플리케이션이 지정한 리소스입니다.An application-specified resource.
METADATAMETADATA 메타데이터 잠금입니다.Metadata locks.
ALLOCATION_UNITALLOCATION_UNIT 할당 단위입니다.An allocation unit.
DATABASEDATABASE 전체 데이터베이스입니다.The entire database.

참고

HoBT 및 TABLE 잠금은 ALTER TABLE의 LOCK_ESCALATION 옵션의 영향을 받을 수 있습니다.HoBT and TABLE locks can be affected by the LOCK_ESCALATION option of ALTER TABLE.

잠금 모드Lock Modes

SQL Server 데이터베이스 엔진SQL Server Database Engine은 동시 트랜잭션이 리소스에 액세스할 수 있는 방법을 결정하는 여러 가지 잠금 모드를 사용하여 리소스를 잠급니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine locks resources using different lock modes that determine how the resources can be accessed by concurrent transactions.

다음 표에서는 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 사용하는 리소스 잠금 모드를 보여 줍니다.The following table shows the resource lock modes that the SQL Server 데이터베이스 엔진SQL Server Database Engine uses.

잠금 모드Lock mode DescriptionDescription
공유(S)Shared (S) SELECT 문처럼 데이터를 변경하거나 업데이트하지 않는 읽기 작업에 사용합니다.Used for read operations that do not change or update data, such as a SELECT statement.
업데이트(U)Update (U) 업데이트할 수 있는 리소스에 사용합니다.Used on resources that can be updated. 여러 개의 세션이 리소스를 읽고, 잠그고, 나중에 업데이트할 때 발생하는 일반적인 교착 상태를 방지합니다.Prevents a common form of deadlock that occurs when multiple sessions are reading, locking, and potentially updating resources later.
배타적(X)Exclusive (X) INSERT, UPDATE, DELETE와 같은 데이터 수정 작업에 사용합니다.Used for data-modification operations, such as INSERT, UPDATE, or DELETE. 여러 개의 업데이트 작업이 같은 리소스에 대해 동시에 이루어지지 못하게 합니다.Ensures that multiple updates cannot be made to the same resource at the same time.
의도Intent 잠금 계층 구조를 만드는 데 사용합니다.Used to establish a lock hierarchy. 의도 잠금의 종류에는 내재된 공유(IS), 내재된 배타(IX), 공유 내재된 배타(SIX)가 있습니다.The types of intent locks are: intent shared (IS), intent exclusive (IX), and shared with intent exclusive (SIX).
스키마Schema 테이블의 스키마에 종속되는 작업이 실행될 때 사용합니다.Used when an operation dependent on the schema of a table is executing. 스키마 잠금에는 스키마 수정(Sch-M)과 스키마 안정성(Sch-S) 잠금이 있습니다.The types of schema locks are: schema modification (Sch-M) and schema stability (Sch-S).
대량 업데이트(BU)Bulk Update (BU) 데이터를 테이블로 대량 복사하는 경우와 TABLOCK 힌트가 지정된 경우에 사용합니다.Used when bulk copying data into a table and the TABLOCK hint is specified.
키 범위Key-range 직렬화 가능 트랜잭션 격리 수준을 사용할 때 쿼리가 읽는 행 범위를 보호합니다.Protects the range of rows read by a query when using the serializable transaction isolation level. 쿼리가 다시 실행될 경우 직렬화 가능 트랜잭션의 쿼리에 대해 반환되는 행을 다른 트랜잭션이 삽입할 수 없도록 합니다.Ensures that other transactions cannot insert rows that would qualify for the queries of the serializable transaction if the queries were run again.

공유 잠금Shared Locks

공유(S) 잠금을 사용하면 비관적 동시성 제어 하에서 동시 트랜잭션이 리소스를 읽을(SELECT) 수 있습니다.Shared (S) locks allow concurrent transactions to read (SELECT) a resource under pessimistic concurrency control. 리소스에 공유(S) 잠금이 설정되어 있는 동안에는 다른 트랜잭션이 데이터를 수정할 수 없습니다.No other transactions can modify the data while shared (S) locks exist on the resource. 트랜잭션 격리 수준을 반복 읽기 이상으로 설정하거나 잠금 힌트를 사용하여 트랜잭션 기간에 대한 공유(S) 잠금을 보유하지 않는 한, 리소스에 대한 공유(S) 잠금은 읽기 작업이 완료되면 바로 해제됩니다.Shared (S) locks on a resource are released as soon as the read operation completes, unless the transaction isolation level is set to repeatable read or higher, or a locking hint is used to retain the shared (S) locks for the duration of the transaction.

업데이트 잠금Update Locks

업데이트(U) 잠금을 사용하면 일반적인 형태의 교착 상태가 방지됩니다.Update (U) locks prevent a common form of deadlock. 반복 읽기 또는 직렬화 가능 트랜잭션의 경우 트랜잭션이 데이터를 읽고, 리소스(페이지 또는 행)에 대한 공유(S) 잠금을 얻은 다음 데이터를 수정하는데 행을 수정할 때는 배타적(X) 잠금으로 잠금을 변환해야 합니다.In a repeatable read or serializable transaction, the transaction reads data, acquiring a shared (S) lock on the resource (page or row), and then modifies the data, which requires lock conversion to an exclusive (X) lock. 두 트랜잭션이 리소스에 대해 공유 모드 잠금을 얻은 다음 데이터를 동시에 업데이트하려고 하면 한 트랜잭션이 배타적(X) 잠금으로 잠금을 변환하려고 합니다.If two transactions acquire shared-mode locks on a resource and then attempt to update data concurrently, one transaction attempts the lock conversion to an exclusive (X) lock. 한 트랜잭션의 배타 잠금은 다른 트랜잭션의 공유 모드 잠금과 호환되지 않으므로 공유 모드를 배타 모드로 변환할 때는 잠금 대기가 발생합니다.The shared-mode-to-exclusive lock conversion must wait because the exclusive lock for one transaction is not compatible with the shared-mode lock of the other transaction; a lock wait occurs. 두 번째 트랜잭션이 해당 업데이트에 대해 배타적(X) 잠금을 얻으려고 합니다.The second transaction attempts to acquire an exclusive (X) lock for its update. 이 경우 두 트랜잭션 모두 배타적(X) 잠금으로 변환 중이고 각각 상대 트랜잭션이 공유 모드 잠금을 해제하기를 기다리므로 교착 상태가 발생합니다.Because both transactions are converting to exclusive (X) locks, and they are each waiting for the other transaction to release its shared-mode lock, a deadlock occurs.

이러한 교착 상태를 방지하려면 업데이트(U) 잠금을 사용합니다.To avoid this potential deadlock problem, update (U) locks are used. 한 번에 한 트랜잭션만 리소스에 대한 업데이트(U) 잠금을 얻을 수 있습니다.Only one transaction can obtain an update (U) lock to a resource at a time. 트랜잭션이 리소스를 수정하면 업데이트(U) 잠금이 배타적(X) 잠금으로 변환됩니다.If a transaction modifies a resource, the update (U) lock is converted to an exclusive (X) lock.

배타 잠금Exclusive Locks

배타적(X) 잠금을 사용하면 동시 트랜잭션이 리소스에 액세스할 수 없습니다.Exclusive (X) locks prevent access to a resource by concurrent transactions. 배타(X) 잠금을 사용하면 다른 트랜잭션이 데이터를 수정할 수 없습니다. 읽기 작업은 NOLOCK 힌트 또는 READ UNCOMMITED 격리 수준을 사용해서만 수행할 수 있습니다.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.

INSERT, UPDATE 및 DELETE 등의 데이터 수정 문은 데이터 수정과 읽기 작업을 함께 수행합니다.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. 예를 들어 UPDATE 문은 다른 테이블과의 조인이 있는 테이블의 행을 수정할 수 있습니다.For example, an UPDATE statement might modify rows in one table based on a join with another table. 이 경우 UPDATE 문은 조인 테이블에서 읽는 행에 대한 공유 잠금과 업데이트되는 행에 대한 배타 잠금을 함께 요청합니다.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.

의도 잠금Intent Locks

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 의도 잠금을 사용하여 잠금 계층 구조 아래쪽에 있는 하위 수준 리소스에 설정되는 공유(S) 잠금 또는 배타적(X) 잠금을 보호합니다.The SQL Server 데이터베이스 엔진SQL Server 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.
  • SQL Server 데이터베이스 엔진SQL Server Database Engine에서 상위 수준 세분성에서 발생하는 잠금 충돌을 보다 효율적으로 발견할 수 있도록 해 줍니다.To improve the efficiency of the SQL Server 데이터베이스 엔진SQL Server Database Engine in detecting lock conflicts at the higher level of granularity.

예를 들어 테이블 내의 페이지 또는 행에 대한 공유(S) 잠금이 요청되기 전에 해당 테이블 수준에서 공유 의도 잠금이 요청됩니다.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. 테이블 수준에서 의도 잠금을 설정하면 이후에 다른 트랜잭션이 해당 페이지를 포함하는 테이블에 대해 배타적(X) 잠금을 얻을 수 없습니다.Setting an intent lock at the table level prevents another transaction from subsequently acquiring an exclusive (X) lock on the table containing that page. SQL Server 데이터베이스 엔진SQL Server Database Engine은 테이블 수준에서만 의도 잠금을 확인하여 트랜잭션이 해당 테이블에 대해 잠금을 얻을 수 있는지 확인하므로 의도 잠금을 사용하면 성능이 향상됩니다.Intent locks improve performance because the SQL Server 데이터베이스 엔진SQL Server 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.

의도 잠금에는 내재된 공유(IS) 잠금, 의도 배타(IX) 잠금, 의도 배타 공유(SIX) 잠금이 있습니다.Intent locks include intent shared (IS), intent exclusive (IX), and shared with intent exclusive (SIX).

잠금 모드Lock mode DescriptionDescription
내재된 공유(IS)(IS)Intent shared (IS) 계층 구조의 아래쪽에 있는 일부 리소스에 대해 요청되거나 확보된 공유 잠금을 보호합니다.Protects requested or acquired shared locks on some (but not all) resources lower in the hierarchy.
의도 배타(IX)Intent exclusive (IX) 계층 구조의 아래쪽에 있는 일부 리소스에 대해 요청되거나 확보된 배타 잠금을 보호합니다.Protects requested or acquired exclusive locks on some (but not all) resources lower in the hierarchy. IX는 IS의 상위 집합으로, 하위 수준 리소스에 대한 공유 잠금 요청도 보호합니다.IX is a superset of IS, and it also protects requesting shared locks on lower level resources.
의도 배타 공유(SIX)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. 최상위 수준 리소스에서는 동시 IS 잠금이 허용됩니다.Concurrent IS locks at the top-level resource are allowed. 예를 들어 테이블에 대한 SIX 잠금을 확보하면 수정되는 페이지에 대한 의도 배타 잠금 및 수정되는 행에 대한 배타 잠금도 동시에 확보됩니다.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. 리소스당 한 번에 하나의 SIX 잠금을 설정할 수 있으므로 다른 트랜잭션이 테이블 수준에서 IS 잠금을 얻어 계층 구조 아래쪽에 있는 리소스를 읽을 수는 있어도 다른 트랜잭션이 리소스를 업데이트할 수는 없습니다.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.
의도 업데이트(IU)Intent update (IU) 계층 구조 아래쪽에 있는 모든 리소스에 대해 요청되거나 확보된 업데이트 잠금을 보호합니다.Protects requested or acquired update locks on all resources lower in the hierarchy. IU 잠금은 페이지 리소스에만 사용됩니다.IU locks are used only on page resources. 업데이트 작업이 발생하면 IU 잠금이 IX 잠금으로 변환됩니다.IU locks are converted to IX locks if an update operation takes place.
공유 의도 업데이트(SIU)Shared intent update (SIU) S 잠금과 IU 잠금이 결합된 것으로, 두 잠금을 별도로 확보한 후 동시에 동시에 보유할 경우 설정됩니다.A combination of S and IU locks, as a result of acquiring these locks separately and simultaneously holding both locks. 예를 들어 트랜잭션이 PAGLOCK 힌트가 있는 쿼리를 실행한 다음 업데이트 작업을 실행하면For example, a transaction executes a query with the PAGLOCK hint and then executes an update operation. PAGLOCK 힌트가 있는 쿼리는 S 잠금을 확보하고 업데이트 작업은 IU 잠금을 확보합니다.The query with the PAGLOCK hint acquires the S lock, and the update operation acquires the IU lock.
업데이트 의도 배타(UIX)Update intent exclusive (UIX) U 잠금과 IX 잠금이 결합된 것으로, 두 잠금을 별도로 확보한 후 동시에 동시에 보유할 경우 설정됩니다.A combination of U and IX locks, as a result of acquiring these locks separately and simultaneously holding both locks.

스키마 잠금Schema Locks

SQL Server 데이터베이스 엔진SQL Server Database Engine은 열을 추가하거나 테이블을 삭제하는 등의 테이블 DDL(데이터 정의 언어) 작업 중에 스키마 수정(Sch-M) 잠금을 사용합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses schema modification (Sch-M) locks during a table data definition language (DDL) operation, such as adding a column or dropping a table. Sch-M 잠금이 유지되는 동안에는 테이블에 대한 동시 액세스가 방지됩니다.During the time that it is held, the Sch-M lock prevents concurrent access to the table. 즉, 잠금이 해제되기 전까지는 Sch-M 잠금이 모든 외부 작업을 차단합니다.This means the Sch-M lock blocks all outside operations until the lock is released.

테이블 잘림 등의 일부 DML(데이터 조작 언어)은 Sch-M 잠금을 사용하여 영향을 받는 테이블에 대한 동시 작업의 액세스를 방지합니다.Some data manipulation language (DML) operations, such as table truncation, use Sch-M locks to prevent access to affected tables by concurrent operations.

SQL Server 데이터베이스 엔진SQL Server Database Engine은 쿼리를 컴파일하고 실행할 때 스키마 안정성(Sch-S) 잠금을 사용합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses schema stability (Sch-S) locks when compiling and executing queries. Sch-S 잠금은 배타적(X) 잠금 등의 트랜잭션 잠금을 차단하지 않습니다.Sch-S locks do not block any transactional locks, including exclusive (X) locks. 따라서 쿼리가 컴파일되는 동안 테이블에 대한 X 잠금이 있는 트랜잭션을 포함하여 다른 트랜잭션이 계속 실행됩니다.Therefore, other transactions, including those with X locks on a table, continue to run while a query is being compiled. 그러나 Sch-M 잠금을 획득하는 동시 DML 작업과 동시 DDL 작업은 테이블에서 수행할 수 없습니다.However, concurrent DDL operations, and concurrent DML operations that acquire Sch-M locks, cannot be performed on the table.

대량 업데이트 잠금Bulk Update Locks

대량 업데이트(BU) 잠금을 사용하면 여러 스레드가 데이터를 동시에 같은 테이블로 대량 로드하는 것은 허용하고, 데이터를 대량 로드하지 않는 다른 프로세스가 테이블에 액세스하는 것은 방지할 수 있습니다.Bulk update (BU) locks allow multiple threads to bulk load data concurrently into the same table while preventing other processes that are not bulk loading data from accessing the table. SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 다음 조건이 모두 충족되면 대량 업데이트(BU) 잠금을 사용합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses bulk update (BU) locks when both of the following conditions are true.

  • Transact-SQLTransact-SQL BULK INSERT 문 또는 OPENROWSET(BULK) 함수를 사용하거나 .NET SqlBulkCopy, OLEDB 빠른 로드 API 또는 ODBC 대량 복사 API와 같은 BULK INSERT 명령 중 하나를 사용하여 데이터를 테이블에 대량 복사합니다.You use the Transact-SQLTransact-SQL BULK INSERT statement, or the OPENROWSET(BULK) function, or you use one of the Bulk Insert API commands such as .NET SqlBulkCopy, OLEDB Fast Load APIs, or the ODBC Bulk Copy APIs to bulk copy data into a table.
  • TABLOCK 힌트를 지정하거나 sp_tableoption 을 사용하여 table lock on bulk load 테이블 옵션을 설정합니다.The TABLOCK hint is specified or the table lock on bulk load table option is set using sp_tableoption.

덜 제한적인 대량 업데이트 잠금을 보유하는 BULK INSERT 문과 달리 TABLOCK 힌트를 사용하는 INSERT INTO...SELECT 문은 테이블에 대해 배타적(X) 잠금을 보유합니다.Unlike the BULK INSERT statement, which holds a less restrictive Bulk Update lock, INSERT INTO...SELECT with the TABLOCK hint holds an exclusive (X) lock on the table. 즉, 병렬 삽입 작업을 사용하여 행을 삽입할 수 없습니다.This means that you cannot insert rows using parallel insert operations.

키 범위 잠금Key-Range Locks

키 범위 잠금은 직렬화 가능 트랜잭션 격리 수준을 사용하는 동안 Transact-SQLTransact-SQL 문에서 읽는 레코드 집합에 포함된 행 범위를 암시적으로 보호합니다.Key-range locks protect a range of rows implicitly included in a record set being read by a Transact-SQLTransact-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.

잠금 호환성Lock Compatibility

잠금 호환성에 따라 여러 트랜잭션이 동시에 같은 리소스에 대한 잠금을 획득할 수 있는지 여부가 결정됩니다.Lock compatibility controls whether multiple transactions can acquire locks on the same resource at the same time. 이미 다른 트랜잭션에서 리소스를 잠근 경우에는 요청된 잠금 모드가 기존 잠금 모드와 호환되어야만 새 잠금 요청이 허용될 수 있습니다.If a resource is already locked by another transaction, a new lock request can be granted only if the mode of the requested lock is compatible with the mode of the existing lock. 요청된 잠금의 모드가 기존 잠금과 호환되지 않을 경우 새 잠금을 요청하는 트랜잭션은 기존 잠금이 해제되거나 잠금 시간 초과 간격이 만료될 때까지 기다립니다.If the mode of the requested lock is not compatible with the existing lock, the transaction requesting the new lock waits for the existing lock to be released or for the lock timeout interval to expire. 예를 들어 배타적 잠금과 호환되는 잠금 모드는 없습니다.For example, no lock modes are compatible with exclusive locks. 배타적(X) 잠금이 설정되어 있는 동안 다른 트랜잭션은 배타적(X) 잠금이 해제될 때까지 해당 리소스에 대해 공유, 업데이트 또는 배타적 잠금을 비롯한 어떠한 유형의 잠금도 획득할 수 없습니다.While an exclusive (X) lock is held, no other transaction can acquire a lock of any kind (shared, update, or exclusive) on that resource until the exclusive (X) lock is released. 리소스에 공유(S) 잠금이 적용된 경우에는 첫 번째 트랜잭션이 완료되지 않아도 다른 트랜잭션이 해당 항목에 대해 공유 잠금 또는 업데이트(U) 잠금을 획득할 수 있습니다.Alternatively, if a shared (S) lock has been applied to a resource, other transactions can also acquire a shared lock or an update (U) lock on that item even if the first transaction has not completed. 그러나 공유 잠금이 해제될 때까지는 다른 트랜잭션이 배타적 잠금을 획득할 수 없습니다.However, other transactions cannot acquire an exclusive lock until the shared lock has been released.

다음 표에서는 가장 일반적인 잠금 모드의 호환성을 보여줍니다.The following table shows the compatibility of the most commonly encountered lock modes.

기존의 허가 모드Existing granted mode
요청 모드Requested mode ISIS SS UU IXIX SIXSIX XX
내재된 공유(IS)(IS)Intent shared (IS) Yes Yes Yes Yes Yes No
공유(S)Shared (S) Yes Yes Yes No No No
업데이트(U)Update (U) Yes Yes No No No No
의도 배타(IX)Intent exclusive (IX) Yes No 아니요No Yes No No
의도 배타 공유(SIX)Shared with intent exclusive (SIX) Yes No No No No No
배타적(X)Exclusive (X) No No No No No No

참고

의도 배타(IX) 잠금은 모든 행이 아닌 일부 행만 업데이트하기 위한 것이므로 IX 잠금 모드와 호환됩니다.An intent exclusive (IX) lock is compatible with an IX lock mode because IX means the intention is to update only some of the rows rather than all of them. 일부 행을 읽거나 업데이트하려고 하는 다른 트랜잭션도 허용됩니다. 단, 해당 행을 다른 트랜잭션이 업데이트하고 있지 않아야 합니다.Other transactions that attempt to read or update some of the rows are also permitted as long as they are not the same rows being updated by other transactions. 두 트랜잭션이 같은 행을 업데이트하려고 시도하는 경우 두 트랜잭션 모두에 테이블 및 페이지 수준의 IX 잠금이 부여됩니다.Further, if two transactions attempt to update the same row, both transactions will be granted an IX lock at table and page level. 하지만 한 트랜잭션에 행 수준의 X 잠금이 부여되므로However, one transaction will be granted an X lock at row level. 다른 트랜잭션은 행 수준 잠금이 제거될 때까지 대기해야 합니다.The other transaction must wait until the row-level lock is removed.

SQL ServerSQL Server에서 사용할 수 있는 모든 잠금 모드의 호환성을 확인하려면 다음 표를 사용합니다.Use the following table to determine the compatibility of all the lock modes available in SQL ServerSQL Server.

lock_conflicts

키 범위 잠금Key-Range Locking

키 범위 잠금은 직렬화 가능 트랜잭션 격리 수준을 사용하는 동안 Transact-SQLTransact-SQL 문에서 읽는 레코드 집합에 포함된 행 범위를 암시적으로 보호합니다.Key-range locks protect a range of rows implicitly included in a record set being read by a Transact-SQLTransact-SQL statement while using the serializable transaction isolation level. 직렬화 가능 격리 수준에서는 트랜잭션 중 실행되는 모든 쿼리가 트랜잭션 중 실행될 때마다 동일한 행 집합을 가져와야 합니다.The serializable isolation level requires that any query executed during a transaction must obtain the same set of rows every time it is executed during the transaction. 키 범위 잠금은 다른 트랜잭션에서 해당 키가 직렬화 가능 트랜잭션에서 읽은 키 범위에 속하는 새 행을 삽입하지 못하도록 하여 이 요구 사항을 보호합니다.A key range lock protects this requirement by preventing other transactions from inserting new rows whose keys would fall in the range of keys read by the serializable transaction.

키 범위 잠금은 가상 읽기를 방지합니다.Key-range locking prevents phantom reads. 또한 행 사이에서 키 범위를 보호하여 트랜잭션에서 액세스하는 레코드 집합에 대한 가상 삽입을 방지합니다.By protecting the ranges of keys between rows, it also prevents phantom insertions into a set of records accessed by a transaction.

키 범위 잠금은 인덱스에 배치되어 시작 키 값과 종료 키 값을 지정합니다.A key-range lock is placed on an index, specifying a beginning and ending key value. 이 잠금은 키 값이 해당 범위에 속하는 모든 행의 삽입, 업데이트 또는 삭제 시도를 차단합니다. 이는 이러한 작업을 수행하려면 먼저 인덱스에 대한 잠금을 획득해야 하기 때문입니다.This lock blocks any attempt to insert, update, or delete any row with a key value that falls in the range because those operations would first have to acquire a lock on the index. 예를 들어 직렬화 가능 트랜잭션은 해당 키 값이 BETWEEN 'AAA' AND 'CZZ' 조건과 일치하는 모든 행을 읽는 SELECT 문을 실행할 수 있습니다.For example, a serializable transaction could issue a SELECT statement that reads all rows whose key values match the condition BETWEEN 'AAA' AND 'CZZ'. ' AAA ' 부터 ' CZZ ' 까지의 범위에 있는 키 값에 대한 키 범위 잠금은 다른 트랜잭션에서 해당 키 값이 ' ADG ' , ' BBD ' 또는 ' CAL ' 과 같이 해당 범위에 있는 행을 삽입하지 못하도록 합니다.A key-range lock on the key values in the range from ' AAA ' to ' CZZ ' prevents other transactions from inserting rows with key values anywhere in that range, such as ' ADG ', ' BBD ', or ' CAL '.

키 범위 잠금 모드Key-Range Lock Modes

키 범위 잠금에는 범위-행 형식으로 지정된 범위 및 행 구성 요소가 모두 포함됩니다.Key-range locks include both a range and a row component specified in range-row format:

  • 범위는 두 개의 연속되는 인덱스 항목 간의 범위를 보호하는 잠금 모드를 나타냅니다.Range represents the lock mode protecting the range between two consecutive index entries.

  • 행은 인덱스 항목을 보호하는 잠금 모드를 나타냅니다.Row represents the lock mode protecting the index entry.

  • 모드는 사용된 혼합 잠금 모드를 나타냅니다.Mode represents the combined lock mode used. 키 범위 잠금 모드는 두 부분으로 구성됩니다.Key-range lock modes consist of two parts. 첫 번째는 인덱스 범위(Range T)를 잠그는 데 사용하는 잠금 유형을 나타내고 두 번째는 특정 키(K)를 잠그는 데 사용하는 잠금 유형을 나타냅니다.The first represents the type of lock used to lock the index range (Range T) and the second represents the lock type used to lock a specific key (K). 두 부분은 T-K 와 같이 하이픈(-)으로 연결됩니다.The two parts are connected with a hyphen (-), such as Range T-K.

    범위Range Row ModeMode DescriptionDescription
    RangeSRangeS SS RangeS-SRangeS-S 공유 범위, 공유 리소스 잠금. 직렬화 가능한 범위 검색입니다.Shared range, shared resource lock; serializable range scan.
    RangeSRangeS UU RangeS-URangeS-U 공유 범위, 업데이트 리소스 잠금, 직렬화 가능한 업데이트 검색입니다.Shared range, update resource lock; serializable update scan.
    RangeIRangeI NullNull RangeI-NRangeI-N 삽입 범위, null 리소스 잠금. 인덱스에 새 키를 삽입하기 전에 범위를 테스트하는 데 사용됩니다.Insert range, null resource lock; used to test ranges before inserting a new key into an index.
    RangeXRangeX XX RangeX-XRangeX-X 배타적 범위, 배타적 리소스 잠금. 범위 내의 키를 업데이트할 때 사용됩니다.Exclusive range, exclusive resource lock; used when updating a key in a range.

참고

내부적 Null 잠금 모드는 다른 모든 잠금 모드와 호환됩니다.The internal Null lock mode is compatible with all other lock modes.

키 범위 잠금 모드에는 겹치는 키 및 범위에서 얻은 다른 잠금과 호환되는 잠금을 보여 주는 호환성 행렬이 있습니다.Key-range lock modes have a compatibility matrix that shows which locks are compatible with other locks obtained on overlapping keys and ranges.

기존의 허가 모드Existing granted mode
요청 모드Requested mode SS UU XX RangeS-SRangeS-S RangeS-URangeS-U RangeI-NRangeI-N RangeX-XRangeX-X
공유(S)Shared (S) Yes Yes 아니요No Yes Yes Yes No
업데이트(U)Update (U) Yes No 아니요No Yes 아니요No Yes No
배타적(X)Exclusive (X) No No No No 아니요No Yes No
RangeS-SRangeS-S Yes Yes 아니요No Yes Yes No No
RangeS-URangeS-U Yes No 아니요No Yes No No No
RangeI-NRangeI-N Yes Yes Yes No 아니요No Yes No
RangeX-XRangeX-X No No No No No No No

변환 잠금Conversion Locks

변환 잠금은 키 범위 잠금이 다른 잠금과 겹칠 때 만들어집니다.Conversion locks are created when a key-range lock overlaps another lock.

잠금 1Lock 1 잠금 2Lock 2 변환 잠금Conversion lock
SS RangeI-NRangeI-N RangeI-SRangeI-S
UU RangeI-NRangeI-N RangeI-URangeI-U
XX RangeI-NRangeI-N RangeI-XRangeI-X
RangeI-NRangeI-N RangeS-SRangeS-S RangeX-SRangeX-S
RangeI-NRangeI-N RangeS-URangeS-U RangeX-URangeX-U

변환 잠금은 다양한 복합 환경에서 짧은 시간 동안 나타날 수 있으며 때로는 동시 프로세스를 실행하는 동안에 나타납니다.Conversion locks can be observed for a short period of time under different complex circumstances, sometimes while running concurrent processes.

직렬화 가능 범위 검색, 단일 인출, 삭제 및 삽입Serializable Range Scan, Singleton Fetch, Delete, and Insert

키 범위 잠금을 사용하면 다음 작업을 직렬화할 수 있습니다.Key-range locking ensures that the following operations are serializable:

  • 범위 검색 쿼리Range scan query
  • 존재하지 않는 행의 단일 인출Singleton fetch of nonexistent row
  • 삭제 작업Delete operation
  • 삽입 작업Insert operation

키 범위 잠금이 발생하려면 다음 조건을 만족해야 합니다.Before key-range locking can occur, the following conditions must be satisfied:

  • 트랜잭션 격리 수준을 SERIALIZABLE로 설정해야 합니다.The transaction-isolation level must be set to SERIALIZABLE.
  • 쿼리 프로세서가 인덱스를 사용하여 범위 필터 조건자를 구현해야 합니다.The query processor must use an index to implement the range filter predicate. 예를 들어 SELECT 문의 WHERE 절은 다음 조건자를 사용하여 범위 조건을 설정할 수 있습니다. ColumnX BETWEEN N ' AAA ' AND N ' CZZ ' .For example, the WHERE clause in a SELECT statement could establish a range condition with this predicate: ColumnX BETWEEN N ' AAA ' AND N ' CZZ '. 키 범위 잠금은 ColumnX 가 인덱스 키 내에 있는 경우에만 얻을 수 있습니다.A key-range lock can only be acquired if ColumnX is covered by an index key.

예제Examples

다음 테이블 및 인덱스는 이어지는 키 범위 잠금 예의 기준으로 사용됩니다.The following table and index are used as a basis for the key-range locking examples that follow.

btree

범위 검색 쿼리Range Scan Query

범위 검색 쿼리가 직렬화 가능인지 확인하려면 같은 트랜잭션 내에서 같은 쿼리를 실행할 때마다 같은 결과를 반환해야 합니다.To ensure a range scan query is serializable, the same query should return the same results each time it is executed within the same transaction. 다른 트랜잭션에서는 범위 스캔 쿼리 내에 새 행을 추가하면 안됩니다. 그렇지 않으면 이러한 행은 가상 삽입이 됩니다.New rows must not be inserted within the range scan query by other transactions; otherwise, these become phantom inserts. 예를 들어 다음 쿼리는 앞 그림의 테이블과 인덱스를 사용합니다.For example, the following query uses the table and index in the previous illustration:

SELECT name  
FROM mytable  
WHERE name BETWEEN 'A' AND 'C';  

키 범위 잠금은 이름이 AdamDale 값 사이에 있는 데이터 행 범위에 해당하는 인덱스 항목에 설정되어 앞의 쿼리에서 한정하는 새 행의 추가 또는 삭제를 방지합니다.Key-range locks are placed on the index entries corresponding to the range of data rows where the name is between the values Adam and Dale, preventing new rows qualifying in the previous query from being added or deleted. 이 범위의 첫 번째 이름은 Adam이지만 이 인덱스 항목에 RangeS-S 모드 키 범위 잠금을 사용하면 Abigail과 같이 A로 시작하는 새 이름을 Adam 앞에 추가할 수 없습니다.Although the first name in this range is Adam, the RangeS-S mode key-range lock on this index entry ensures that no new names beginning with the letter A can be added before Adam, such as Abigail. 마찬가지로 Dale의 인덱스 항목에 RangeS-S 키 범위 잠금을 사용하면 Clive와 같이 C로 시작하는 새 이름을 Carlos 뒤에 추가할 수 없습니다.Similarly, the RangeS-S key-range lock on the index entry for Dale ensures that no new names beginning with the letter C can be added after Carlos, such as Clive.

참고

보유한 RangeS-S 잠금 수는 n+1입니다. 여기서 n 은 쿼리를 만족하는 행 수입니다.The number of RangeS-S locks held is n+1, where n is the number of rows that satisfy the query.

존재하지 않는 데이터의 단일 인출Singleton Fetch of Nonexistent Data

트랜잭션 내의 쿼리가 존재하지 않는 행을 선택하려고 하면 같은 트랜잭션 내에서 나중에 쿼리를 실행해도 같은 결과를 반환해야 합니다.If a query within a transaction attempts to select a row that does not exist, issuing the query at a later point within the same transaction has to return the same result. 다른 트랜잭션도 존재하지 않는 행을 삽입할 수 없습니다.No other transaction can be allowed to insert that nonexistent row. 다음과 같은 쿼리를 예로 들 수 있습니다.For example, given this query:

SELECT name  
FROM mytable  
WHERE name = 'Bill';  

이 경우 Ben이라는 이름이 인접한 두 인덱스 항목 사이에 삽입되므로 키 범위 잠금은 Bing부터 Bill까지의 이름 범위에 해당하는 인덱스 항목에 적용됩니다.A key-range lock is placed on the index entry corresponding to the name range from Ben to Bing because the name Bill would be inserted between these two adjacent index entries. RangeS-S 모드 키 범위 잠금은 인덱스 항목 Bing에 적용됩니다.The RangeS-S mode key-range lock is placed on the index entry Bing. 이렇게 되면 다른 모든 트랜잭션이 Bill 등의 값을 인덱스 항목 BenBing 사이에 삽입할 수 없습니다.This prevents any other transaction from inserting values, such as Bill, between the index entries Ben and Bing.

삭제 작업Delete Operation

트랜잭션 내에서 값을 삭제할 때는 트랜잭션이 삭제 작업을 수행하는 동안 값이 속하는 범위를 잠글 필요가 없습니다.When deleting a value within a transaction, the range the value falls into does not have to be locked for the duration of the transaction performing the delete operation. 삭제된 키 값을 트랜잭션이 끝날 때까지 잠그기만 해도 직렬화 기능이 유지됩니다.Locking the deleted key value until the end of the transaction is sufficient to maintain serializability. 다음과 같은 DELETE 문을 예로 들 수 있습니다.For example, given this DELETE statement:

DELETE mytable  
WHERE name = 'Bob';  

배타적(X) 잠금이 Bob이라는 이름에 해당하는 인덱스 항목에 설정되어 있습니다.An exclusive (X) lock is placed on the index entry corresponding to the name Bob. 다른 트랜잭션은 삭제된 값인 Bob 전후에 값을 삽입하거나 삭제할 수 있습니다.Other transactions can insert or delete values before or after the deleted value Bob. 그러나 값 Bob을 읽거나 삽입하거나 삭제하려는 트랜잭션은 삭제 트랜잭션이 커밋되거나 롤백될 때까지 차단됩니다.However, any transaction that attempts to read, insert, or delete the value Bob will be blocked until the deleting transaction either commits or rolls back.

범위 삭제는 세 가지 기본 잠금 모드인 행 잠금, 페이지 잠금 또는 테이블 잠금을 사용하여 실행될 수 있습니다.Range delete can be executed using three basic lock modes: row, page, or table lock. 행, 페이지 또는 테이블 잠금 전략은 쿼리 최적화 프로그램에 의해 결정되거나 ROWLOCK, PAGLOCK 또는 TABLOCK 등의 쿼리 최적화 프로그램 힌트를 통해 사용자가 지정할 수 있습니다.The row, page, or table locking strategy is decided by Query Optimizer or can be specified by the user through Query Optimizer hints such as ROWLOCK, PAGLOCK, or TABLOCK. PAGLOCK 또는 TABLOCK을 사용하는 경우 이 페이지에서 모든 행이 삭제되면 SQL Server 데이터베이스 엔진SQL Server Database Engine은 즉시 인덱스 페이지 할당을 해제합니다.When PAGLOCK or TABLOCK is used, the SQL Server 데이터베이스 엔진SQL Server Database Engine immediately deallocates an index page if all rows are deleted from this page. 반대로 ROWLOCK을 사용하면 삭제된 모든 행이 삭제된 것으로 표시만 되고 나중에 백그라운드 태스크를 사용하여 인덱스 페이지에서 제거됩니다.In contrast, when ROWLOCK is used, all deleted rows are marked only as deleted; they are removed from the index page later using a background task.

삽입 작업Insert Operation

트랜잭션 내에서 값을 삽입할 때는 트랜잭션이 삽입 작업을 수행하는 동안 값이 속하는 범위를 잠글 필요가 없습니다.When inserting a value within a transaction, the range the value falls into does not have to be locked for the duration of the transaction performing the insert operation. 삽입된 키 값을 트랜잭션이 끝날 때까지 잠그기만 해도 직렬화 기능이 유지됩니다.Locking the inserted key value until the end of the transaction is sufficient to maintain serializability. 다음과 같은 INSERT 문을 예로 들 수 있습니다.For example, given this INSERT statement:

INSERT mytable VALUES ('Dan');  

범위를 테스트하기 위해 RangeI-N 모드 키 범위 잠금이 David 이름에 해당하는 인덱스 항목에 적용됩니다.The RangeI-N mode key-range lock is placed on the index entry corresponding to the name David to test the range. 잠금이 허용되면 Dan이 삽입되고 Dan 값에 배타적(X) 잠금이 적용됩니다.If the lock is granted, Dan is inserted and an exclusive (X) lock is placed on the value Dan. Range-N 모드 키 범위 잠금은 범위를 테스트하는 데만 필요하며 트랜잭션이 삽입 작업을 수행하는 동안에는 보유되지 않습니다.The RangeI-N mode key-range lock is necessary only to test the range and is not held for the duration of the transaction performing the insert operation. 다른 트랜잭션은 삽입된 값 Dan 전후에 값을 삽입하거나 삭제할 수 있습니다.Other transactions can insert or delete values before or after the inserted value Dan. 그러나 값 Dan을 읽거나 삽입하거나 삭제하려는 트랜잭션은 삽입 트랜잭션이 커밋되거나 롤백될 때까지 차단됩니다.However, any transaction attempting to read, insert, or delete the value Dan will be locked until the inserting transaction either commits or rolls back.

잠금 에스컬레이션Lock Escalation

잠금 에스컬레이션은 많은 수의 미세 잠금을 더 적은 수의 성긴 잠금으로 변환하여 동시성 경합 가능성은 높이고 시스템 오버헤드는 줄이는 프로세스입니다.Lock escalation is the process of converting many fine-grain locks into fewer coarse-grain locks, reducing system overhead while increasing the probability of concurrency contention.

SQL Server 데이터베이스 엔진SQL Server Database Engine는 하위 수준의 잠금을 획득할 때 더 하위 수준의 개체를 포함하는 개체에 의도 잠금도 배치합니다.As the SQL Server 데이터베이스 엔진SQL Server Database Engine acquires low-level locks, it also places intent locks on the objects that contain the lower-level objects:

  • 행 또는 인덱스 키 범위를 잠그는 경우 데이터베이스 엔진Database Engine는 행 또는 키를 포함하는 페이지에 의도 잠금을 배치합니다.When locking rows or index key ranges, the 데이터베이스 엔진Database Engine places an intent lock on the pages that contain the rows or keys.
  • 페이지를 잠그는 경우 데이터베이스 엔진Database Engine는 페이지를 포함하는 더 상위 수준의 개체에 의도 잠금을 배치합니다.When locking pages, the 데이터베이스 엔진Database Engine places an intent lock on the higher level objects that contain the pages. 개체에 배치된 의도 잠금 외에도 다음 개체에 대해 의도 페이지 잠금이 요청됩니다.In addition to intent lock on the object, intent page locks are requested on the following objects:
    • 비클러스터형 인덱스의 리프 수준 페이지Leaf-level pages of nonclustered indexes
    • 클러스터형 인덱스의 데이터 페이지Data pages of clustered indexes
    • 힙 데이터 페이지Heap data pages

데이터베이스 엔진Database Engine는 동일한 문에 대해 행 잠금과 페이지 잠금을 모두 수행하여 잠금 수를 최소화하고 잠금 에스컬레이션이 필요할 가능성을 낮출 수 있습니다.The 데이터베이스 엔진Database Engine might do both row and page locking for the same statement to minimize the number of locks and reduce the likelihood that lock escalation will be necessary. 예를 들어 데이터베이스 엔진은 비클러스터형 인덱스에는 페이지 잠금을 배치(쿼리를 만족시키기 위해 인덱스 노드에서 충분히 인접한 키가 선택된 경우)하고 데이터에는 행 잠금을 배치할 수 있습니다.For example, the Database Engine could place page locks on a nonclustered index (if enough contiguous keys in the index node are selected to satisfy the query) and row locks on the data.

데이터베이스 엔진Database Engine은 잠금을 에스컬레이션하기 위해 테이블의 의도 잠금을 해당 전체 잠금으로 변경하려고 시도합니다. 예를 들어 의도 배타(IX) 잠금을 배타(X) 잠금으로 변경하거나 내재된 공유(IS) 잠금을 공유(S) 잠금으로 변경하려고 시도합니다.To escalate locks, the 데이터베이스 엔진Database Engine attempts to change the intent lock on the table to the corresponding full lock, for example, changing an intent exclusive (IX) lock to an exclusive (X) lock, or an intent shared (IS) lock to a shared (S) lock). 잠금 에스컬레이션 시도가 성공하여 전체 테이블 잠금을 획득하면 힙이나 인덱스에서 트랜잭션이 보유한 모든 힙 또는 B-트리, 페이지(PAGE) 또는 행 수준(RID) 잠금이 해제됩니다.If the lock escalation attempt succeeds and the full table lock is acquired, then all heap or B-tree, page (PAGE), or row-level (RID) locks held by the transaction on the heap or index are released. 전체 잠금을 획득할 수 없는 경우에는 해당 시점에서 잠금 에스컬레이션이 발생하지 않고 데이터베이스 엔진은 행, 키 또는 페이지 잠금 획득을 계속 시도합니다.If the full lock cannot be acquired, no lock escalation happens at that time and the Database Engine will continue to acquire row, key, or page locks.

데이터베이스 엔진Database Engine은 행 또는 키 범위 잠금을 페이지 잠금으로 에스컬레이션하지 않고 곧바로 테이블 잠금으로 에스컬레이션합니다.The 데이터베이스 엔진Database Engine does not escalate row or key-range locks to page locks, but escalates them directly to table locks. 마찬가지로 페이지 잠금도 항상 테이블 잠금으로 에스컬레이션됩니다.Similarly, page locks are always escalated to table locks. 분할된 테이블의 잠금이 테이블 잠금이 아니라 관련된 파티션에 대한 HoBT 수준으로 에스컬레이션될 수 있습니다.Locking of partitioned tables can escalate to the HoBT level for the associated partition instead of to the table lock. HoBT 수준 잠금이 해당 파티션에 대해 정렬된 HoBT를 반드시 잠그는 것은 아닙니다.A HoBT-level lock does not necessarily lock the aligned HoBTs for the partition.

참고

HoBT 수준 잠금은 일반적으로 동시성을 증가시키지만 각각 다른 파티션을 잠그는 트랜잭션이 배타적 잠금을 다른 파티션으로 확장하려는 경우 교착 상태가 발생할 수도 있습니다.HoBT-level locks usually increase concurrency, but introduce the potential for deadlocks when transactions that are locking different partitions each want to expand their exclusive locks to the other partitions. 경우에 따라 TABLE 잠금 세분성이 향상될 수도 있습니다.In rare instances, TABLE locking granularity might perform better.

동시 트랜잭션이 보유한 잠금의 충돌로 인해 잠금 에스컬레이션 시도가 실패하면 데이터베이스 엔진Database Engine은 트랜잭션이 획득한 추가 1,250개의 잠금 각각에 대해 잠금 에스컬레이션을 다시 시도합니다.If a lock escalation attempt fails because of conflicting locks held by concurrent transactions, the 데이터베이스 엔진Database Engine will retry the lock escalation for each additional 1,250 locks acquired by the transaction.

각 에스컬레이션 이벤트는 주로 단일 Transact-SQLTransact-SQL 문의 수준에서 작동합니다.Each escalation event operates primarily at the level of a single Transact-SQLTransact-SQL statement. 이벤트가 시작되면 데이터베이스 엔진Database Engine은 에스컬레이션 임계값 요구 사항이 충족되는 경우 활성 문에서 참조한 테이블 중에서 현재 트랜잭션이 소유한 모든 잠금을 에스컬레이션하려고 시도합니다.When the event starts, the 데이터베이스 엔진Database Engine attempts to escalate all the locks owned by the current transaction in any of the tables that have been referenced by the active statement provided it meets the escalation threshold requirements. 문이 테이블에 액세스하기 전에 에스컬레이션 이벤트가 시작되면 해당 테이블의 잠금에 대한 에스컬레이션은 시도되지 않습니다.If the escalation event starts before the statement has accessed a table, no attempt is made to escalate the locks on that table. 잠금 에스컬레이션이 성공한 경우 테이블이 현재 문에서 참조되고 에스컬레이션 이벤트에 포함되어 있다면 이전 문에서 트랜잭션이 획득하여 이벤트 시작 시에도 여전히 보유하는 모든 잠금이 에스컬레이션됩니다.If lock escalation succeeds, any locks acquired by the transaction in a previous statement and still held at the time the event starts will be escalated if the table is referenced by the current statement and is included in the escalation event.

예를 들어 다음 작업을 수행하는 세션이 있다고 가정합니다.For example, assume that a session performs these operations:

  • 트랜잭션을 시작합니다.Begins a transaction.
  • TableA를 업데이트합니다.Updates TableA. 그러면 TableA에 트랜잭션이 완료될 때까지 보유되는 배타 행 잠금이 생성됩니다.This generates exclusive row locks in TableA that are held until the transaction completes.
  • TableB를 업데이트합니다.Updates TableB. 그러면 TableB에 트랜잭션이 완료될 때까지 보유되는 배타 행 잠금이 생성됩니다.This generates exclusive row locks in TableB that are held until the transaction completes.
  • TableATableC를 조인하는 SELECT를 수행합니다.Performs a SELECT that joins TableA with TableC. 쿼리 실행 계획에 따라 행은 TableC에서 검색되기 전에 TableA에서 검색되어야 합니다.The query execution plan calls for the rows to be retrieved from TableA before the rows are retrieved from TableC.
  • SELECT 문은 TableC에 액세스하기 전에 TableA에서 행을 검색하는 동안 잠금 에스컬레이션을 트리거합니다.The SELECT statement triggers lock escalation while it is retrieving rows from TableA and before it has accessed TableC.

잠금 에스컬레이션이 성공하면 TableA에서 세션이 보유한 잠금만 에스컬레이션됩니다.If lock escalation succeeds, only the locks held by the session on TableA are escalated. 여기에는 SELECT 문의 공유 잠금과 이전 UPDATE 문의 배타 잠금이 모두 포함됩니다.This includes both the shared locks from the SELECT statement and the exclusive locks from the previous UPDATE statement. 잠금 에스컬레이션을 수행할지 결정하기 위해 세션이 SELECT 문에 대해 TableA에서 획득한 잠금 수가 계산되는 동안 에스컬레이션이 성공하면 TableA에서 세션이 보유한 모든 잠금은 테이블의 배타 잠금으로 에스컬레이션되고 TableA에서 의도 잠금을 포함하여 세분성이 더 낮은 다른 모든 잠금은 해제됩니다.While only the locks the session acquired in TableA for the SELECT statement are counted to determine if lock escalation should be done, once escalation is successful all locks held by the session in TableA are escalated to an exclusive lock on the table, and all other lower-granularity locks, including intent locks, on TableA are released.

SELECT 문에 TableB에 대한 활성 참조가 없기 때문에 TableB의 잠금 에스컬레이션은 시도되지 않습니다.No attempt is made to escalate locks on TableB because there was no active reference to TableB in the SELECT statement. 마찬가지로 에스컬레이션이 발생할 때 아직 액세스되지 않았기 때문에 에스컬레이션되지 않은 TableC의 잠금에는 에스컬레이션이 시도되지 않습니다.Similarly no attempt is made to escalate the locks on TableC, which are not escalated because it had not yet been accessed when the escalation occurred.

잠금 에스컬레이션 임계값Lock Escalation Thresholds

잠금 에스컬레이션은 ALTER TABLE SET LOCK_ESCALATION 옵션을 사용하여 테이블에서 잠금 에스컬레이션을 사용하지 않도록 설정하지 않은 경우와 다음 조건 중 하나에 해당하는 경우 트리거됩니다.Lock escalation is triggered when lock escalation is not disabled on the table by using the ALTER TABLE SET LOCK_ESCALATION option, and when either of the following conditions exists:

  • 단일 Transact-SQLTransact-SQL 문이 분할되지 않은 단일 테이블이나 인덱스에 대해 5,000개 이상의 잠금을 획득한 경우A single Transact-SQLTransact-SQL statement acquires at least 5,000 locks on a single nonpartitioned table or index.
  • 단일 Transact-SQLTransact-SQL 문이 분할된 테이블의 단일 파티션에 대해 5,000개 이상의 잠금을 획득하고 ALTER TABLE SET LOCK_ESCALATION 옵션이 AUTO로 설정된 경우A single Transact-SQLTransact-SQL statement acquires at least 5,000 locks on a single partition of a partitioned table and the ALTER TABLE SET LOCK_ESCALATION option is set to AUTO.
  • 데이터베이스 엔진Database Engine 인스턴스의 잠금 수가 메모리 또는 구성 임계값을 초과한 경우The number of locks in an instance of the 데이터베이스 엔진Database Engine exceeds memory or configuration thresholds.

잠금 충돌로 인해 잠금을 에스컬레이션할 수 없는 경우 데이터베이스 엔진Database Engine은 1,250개의 잠금이 새로 획득될 때마다 주기적으로 잠금 에스컬레이션을 트리거합니다.If locks cannot be escalated because of lock conflicts, the 데이터베이스 엔진Database Engine periodically triggers lock escalation at every 1,250 new locks acquired.

Transact-SQL 문의 에스컬레이션 임계값Escalation Threshold for a Transact-SQL Statement

데이터베이스 엔진Database Engine에서 새로 획득한 잠금 1,250개마다 가능한 에스컬레이션을 검사할 때 잠금 에스컬레이션은 Transact-SQLTransact-SQL 문에서 테이블의 단일 참조에 대해 5,000개 이상의 잠금을 획득한 경우에만 발생합니다.When the 데이터베이스 엔진Database Engine checks for possible escalations at every 1,250 newly acquired locks, a lock escalation will occur if and only if a Transact-SQLTransact-SQL statement has acquired at least 5,000 locks on a single reference of a table. 잠금 에스컬레이션은 Transact-SQLTransact-SQL 문에서 테이블의 단일 참조에 대해 5,000개 이상의 잠금을 획득한 경우 트리거됩니다.Lock escalation is triggered when a Transact-SQLTransact-SQL statement acquires at least 5,000 locks on a single reference of a table. 예를 들어 문이 한 인덱스에서 3,000개의 잠금을 획득하고 동일한 테이블의 다른 인덱스에서도 3,000개의 잠금을 획득하는 경우에는 잠금 에스컬레이션이 트리거되지 않습니다.For example, lock escalation is not triggered if a statement acquires 3,000 locks in one index and 3,000 locks in another index of the same table. 마찬가지로, 문에 테이블에 대한 자체 조인이 있고 테이블에 대한 각각의 참조가 해당 테이블에서 3,000개의 잠금만 획득하는 경우에는 잠금 에스컬레이션이 트리거되지 않습니다.Similarly, lock escalation is not triggered if a statement has a self join on a table, and each reference to the table only acquires 3,000 locks in the table.

잠금 에스컬레이션은 에스컬레이션이 트리거될 때 액세스한 테이블에 대해서만 발생합니다.Lock escalation only occurs for tables that have been accessed at the time the escalation is triggered. 단일 SELECT 문이 이 시퀀스에서 TableA, TableBTableC의 3개 테이블에 액세스하는 조인이라고 가정합니다.Assume that a single SELECT statement is a join that accesses three tables in this sequence: TableA, TableB, and TableC. 이 문은 TableA에 대한 클러스터형 인덱스에서 3,000개의 행 잠금을 획득하고 TableB에 대한 클러스터형 인덱스에서 5,000개 이상의 행 잠금을 획득하지만 TableC에는 아직 액세스하지 않았습니다.The statement acquires 3,000 row locks in the clustered index for TableA and at least 5,000 row locks in the clustered index for TableB, but has not yet accessed TableC. 데이터베이스 엔진Database Engine에서 이 문이 TableB에서 5,000개 이상의 행 잠금을 획득한 것을 검색하면 TableB에서 현재 트랜잭션이 보유한 모든 잠금을 에스컬레이션하려고 시도합니다.When the 데이터베이스 엔진Database Engine detects that the statement has acquired at least 5,000 row locks in TableB, it attempts to escalate all locks held by the current transaction on TableB. 또한 TableA에서 현재 트랜잭션이 보유한 모든 잠금을 에스컬레이션하려고 시도하지만 TableA의 잠금 수가 5,000개 미만이므로 에스컬레이션은 발생하지 않습니다.It also attempts to escalate all locks held by the current transaction on TableA, but since the number of locks on TableA is less than 5,000, the escalation will not succeed. 에스컬레이션이 발생할 때 아직 액세스되지 않았으므로 TableC에 대해서는 잠금 에스컬레이션이 시도되지 않습니다.No lock escalation is attempted for TableC because it had not yet been accessed when the escalation occurred.

데이터베이스 엔진 인스턴스의 에스컬레이션 임계값Escalation Threshold for an Instance of the Database Engine

잠금 수가 잠금 에스컬레이션에 대한 메모리 임계값보다 커지면 데이터베이스 엔진Database Engine에서 잠금 에스컬레이션을 트리거합니다.Whenever the number of locks is greater than the memory threshold for lock escalation, the 데이터베이스 엔진Database Engine triggers lock escalation. 메모리 임계값은 다음과 같은 잠금 구성 옵션의 설정에 따라 다릅니다.The memory threshold depends on the setting of the locks configuration option:

  • 잠금 옵션을 기본값인 0으로 설정하면 잠금 개체에서 사용하는 메모리가 AWE 메모리를 제외하고 데이터베이스 엔진에서 사용하는 메모리의 24%일 때 잠금 에스컬레이션 임계값에 도달합니다.If the locks option is set to its default setting of 0, then the lock escalation threshold is reached when the memory used by lock objects is 24 percent of the memory used by the Database Engine, excluding AWE memory. 잠금을 나타내는 데 사용되는 데이터 구조의 길이는 약 100바이트입니다.The data structure used to represent a lock is approximately 100 bytes long. 데이터베이스 엔진이 다양한 작업에 맞추어 동적으로 메모리를 획득하거나 해제하기 때문에 이 임계값은 동적입니다.This threshold is dynamic because the Database Engine dynamically acquires and frees memory to adjust for varying workloads.

  • 잠금 옵션을 0 이외의 값으로 설정하면 잠금 에스컬레이션 임계값은 잠금 옵션 값의 40%이고 메모리가 가중되는 경우에는 40% 미만입니다.If the locks option is a value other than 0, then the lock escalation threshold is 40 percent (or less if there is a memory pressure) of the value of the locks option.

데이터베이스 엔진Database Engine은 에스컬레이션을 수행하기 위해 모든 세션에서 모든 활성 문을 선택할 수 있으며 인스턴스에 사용된 잠금 메모리가 임계값보다 높게 유지되는 경우에는 1,250개의 새 잠금마다 에스컬레이션을 수행할 문을 선택합니다.The 데이터베이스 엔진Database Engine can choose any active statement from any session for escalation, and for every 1,250 new locks it will choose statements for escalation as long as the lock memory used in the instance remains above the threshold.

혼합 잠금 유형 에스컬레이션Escalating Mixed Lock Types

잠금 에스컬레이션이 발생하면 힙이나 인덱스에 대해 선택한 잠금은 더 하위 수준의 가장 제한적인 잠금에 대한 요구 사항도 충분히 만족시킬 수 있습니다.When lock escalation occurs, the lock selected for the heap or index is strong enough to meet the requirements of the most restrictive lower level lock.

예를 들어 하나의 세션이 있다고 가정합니다.For example, assume a session:

  • 트랜잭션을 시작합니다.Begins a transaction.
  • 클러스터형 인덱스를 포함하는 테이블을 업데이트합니다.Updates a table containing a clustered index.
  • 동일한 테이블을 참조하는 SELECT 문을 실행합니다.Issues a SELECT statement that references the same table.

UPDATE 문은 다음 잠금을 획득합니다.The UPDATE statement acquires these locks:

  • 업데이트된 데이터 행에 대한 배타(X) 잠금Exclusive (X) locks on the updated data rows.
  • 이러한 행을 포함하는 클러스터형 인덱스 페이지에 대한 의도 배타(IX) 잠금Intent exclusive (IX) locks on the clustered index pages containing those rows.
  • 클러스터형 인덱스에 대한 IX 잠금 및 테이블에 대한 IX 잠금An IX lock on the clustered index and another on the table.

SELECT 문은 다음 잠금을 획득합니다.The SELECT statement acquires these locks:

  • 행이 UPDATE 문에서 X 잠금으로 아직 보호되지 않은 경우 SELECT 문이 읽는 모든 데이터 행에 대한 공유(S) 잠금Shared (S) locks on all data rows it reads, unless the row is already protected by an X lock from the UPDATE statement.
  • 페이지가 IX 잠금으로 아직 보호되지 않은 경우 해당 행을 포함하는 모든 클러스터형 인덱스 페이지에 대한 내재된 공유 잠금Intent Share locks on all clustered index pages containing those rows, unless the page is already protected by an IX lock.
  • 이미 IX 잠금으로 보호되기 때문에 클러스터형 인덱스나 테이블에 대한 잠금은 없습니다.No lock on the clustered index or table because they are already protected by IX locks.

SELECT 문이 잠금 에스컬레이션을 트리거하기에 충분한 잠금을 획득하고 에스컬레이션이 성공하면 테이블에 대한 IX 잠금이 X 잠금으로 변환되고 모든 행, 페이지 및 인덱스 잠금이 해제됩니다.If the SELECT statement acquires enough locks to trigger lock escalation and the escalation succeeds, the IX lock on the table is converted to an X lock, and all the row, page, and index locks are freed. 업데이트와 읽기는 모두 테이블에 대한 X 잠금으로 보호됩니다.Both the updates and reads are protected by the X lock on the table.

잠금 및 에스컬레이션 줄이기Reducing Locking and Escalation

대부분의 경우 데이터베이스 엔진Database Engine은 잠금 및 잠금 에스컬레이션에 대한 기본 설정으로 작동할 때 최상의 성능을 발휘합니다.In most cases, the 데이터베이스 엔진Database Engine delivers the best performance when operating with its default settings for locking and lock escalation. 데이터베이스 엔진Database Engine 인스턴스에서 많은 수의 잠금이 생성되고 잠금 에스컬레이션이 자주 발생하면 다음과 같이 잠금 수를 줄이는 것이 좋습니다.If an instance of the 데이터베이스 엔진Database Engine generates a lot of locks and is seeing frequent lock escalations, consider reducing the amount of locking by:

  • 읽기 작업에서 공유 잠금을 생성하지 않는 격리 수준 사용:Using an isolation level that does not generate shared locks for read operations:

    • READ_COMMITTED_SNAPSHOT 데이터베이스 옵션이 ON으로 설정된 READ COMMITTED 격리 수준READ COMMITTED isolation level when the READ_COMMITTED_SNAPSHOT database option is ON.
    • SNAPSHOT 격리 수준SNAPSHOT isolation level.
    • READ UNCOMMITTED 격리 수준.READ UNCOMMITTED isolation level. 이 수준은 커밋되지 않은 읽기로 작동할 수 있는 시스템에서만 사용할 수 있습니다.This can only be used for systems that can operate with dirty reads.

    참고

    격리 수준 변경은 데이터베이스 엔진Database Engine 인스턴스의 모든 테이블에 영향을 미칩니다.Changing the isolation level affects all tables on the instance of the 데이터베이스 엔진Database Engine.

  • 데이터베이스 엔진이 행 잠금 대신 페이지, 힙 또는 인덱스 잠금을 사용하도록 PAGLOCK 또는 TABLOCK 테이블 힌트 사용.Using the PAGLOCK or TABLOCK table hints to have the Database Engine use page, heap, or index locks instead of row locks. 그러나 이 옵션을 사용하면 한 사용자가 동일한 데이터에 액세스하려는 다른 사용자를 차단하는 문제가 증가하므로 동시 사용자가 많은 시스템에서 이 옵션을 사용하면 안 됩니다.Using this option, however, increases the problems of users blocking other users attempting to access the same data and should not be used in systems with more than a few concurrent users.

  • 분할된 테이블의 경우 ALTER TABLE의 LOCK_ESCALATION 옵션을 사용하면 테이블 수준이 아니라 HoBT 수준으로 잠금을 에스컬레이션하거나 잠금 에스컬레이션을 사용하지 않도록 설정할 수 있습니다.For partitioned tables, use the LOCK_ESCALATION option of ALTER TABLE to escalate locks to the HoBT level instead of the table or to disable lock escalation.

  • 큰 일괄 작업을 여러 개의 작은 작업으로 분할합니다.Break up large batch operations into several smaller operations. 예를 들어 다음 쿼리를 실행하여 감사 테이블에서 수십만 개의 오래된 레코드를 제거하고, 다른 사용자를 차단하는 잠금 에스컬레이션이 발생했다고 가정합니다.For example, suppose you ran the following query to remove several hundred thousand old records from an audit table, and then you found that it caused a lock escalation that blocked other users:

    DELETE FROM LogMessages WHERE LogDate < '2/1/2002'
    

    이러한 레코드를 한 번에 수백 개씩 제거하면 트랜잭션당 누적된 잠금 수를 크게 줄이고 잠금 에스컬레이션을 방지할 수 있습니다.By removing these records a few hundred at a time, you can dramatically reduce the number of locks that accumulate per transaction and prevent lock escalation. 다음은 그 예입니다.For example:

    SET ROWCOUNT 500
    delete_more:
      DELETE FROM LogMessages WHERE LogDate < '2/1/2002'
    IF @@ROWCOUNT > 0 GOTO delete_more
    SET ROWCOUNT 0
    
  • 쿼리를 최대한 효율적으로 만들어 쿼리 잠금 범위를 좁힙니다.Reduce a query's lock footprint by making the query as efficient as possible. 대규모 검색 또는 대량의 책갈피 조회로 인해 잠금 에스컬레이션 가능성이 증가할 수 있습니다. 또한 교착 상태 가능성이 증가하고, 일반적으로 동시성 및 성능에 부정적인 영향을 미칩니다.Large scans or large numbers of Bookmark Lookups may increase the chance of lock escalation; additionally, it increases the chance of deadlocks, and generally adversely affects concurrency and performance. 잠금 에스컬레이션을 유발한 쿼리를 찾은 후 새 인덱스를 만들거나 기존 인덱스에 열을 추가하여 인덱스 또는 테이블 검색을 제거하고 인덱스 검색의 효율성을 극대화하는 기회를 찾습니다.After you find the query that causes lock escalation, look for opportunities to create new indexes or to add columns to an existing index to remove index or table scans and to maximize the efficiency of index seeks. 데이터베이스 엔진 튜닝 관리자를 사용하여 쿼리에 대한 자동 인덱스 분석을 수행하는 것이 좋습니다.Consider using the Database Engine Tuning Advisor to perform an automatic index analysis on the query. 자세한 내용은 자습서: 데이터베이스 엔진 튜닝 관리자를 참조하세요.For more information, see Tutorial: Database Engine Tuning Advisor. 이러한 최적화의 한 가지 목표는 인덱스 검색 시 최소한의 행을 반환하여 책갈피 조회 비용을 최소화하는 것입니다(특정 쿼리에 대한 인덱스의 선택도 극대화).One goal of this optimization is to make index seeks return as few rows as possible to minimize the cost of Bookmark Lookups (maximize the selectivity of the index for the particular query). 데이터베이스 엔진Database Engine에서 책갈피 조회 논리 연산자가 여러 행을 반환할 수 있는 것으로 추정하는 경우 PREFETCH를 사용하여 책갈피 조회를 수행할 수 있습니다.If the 데이터베이스 엔진Database Engine estimates that a Bookmark Lookup logical operator may return many rows, it may use a PREFETCH to perform the bookmark lookup. 데이터베이스 엔진Database Engine에서 책갈피 조회를 위해 PREFETCH를 사용하는 경우 쿼리 일부의 트랜잭션 격리 수준을 쿼리 일부에 대한 반복 읽기로 높여야 합니다.If the 데이터베이스 엔진Database Engine does use PREFETCH for a bookmark lookup, it must increase the transaction isolation level of a portion of the query to repeatable read for a portion of the query. 이것은 커밋된 읽기 격리 수준에서 SELECT 문과 유사한 것이 (클러스터형 인덱스 및 비클러스터형 인덱스 모두에서) 수천 개의 키 잠금을 획득할 수 있으므로 해당 쿼리가 잠금 에스컬레이션 임계값을 초과하게 될 수 있음을 의미합니다.This means that what may look similar to a SELECT statement at a read-committed isolation level may acquire many thousands of key locks (on both the clustered index and one nonclustered index), which can cause such a query to exceed the lock escalation thresholds. 이는 에스컬레이션된 잠금이 공유 테이블 잠금이지만 일반적으로 기본값인 커밋된 읽기 격리 수준에서 표시되지 않는 경우에 특히 중요합니다.This is especially important if you find that the escalated lock is a shared table lock, which, however, is not commonly seen at the default read-committed isolation level. 책갈피 조회 WITH PREFETCH 절로 인해 에스컬레이션이 발생하는 경우 쿼리 계획의 책갈피 조회 논리 연산자 아래에 있는 인덱스 검색(Seek) 또는 인덱스 검색(Scan) 논리 연산자에 표시되는 비클러스터형 인덱스에 열을 추가하는 것이 좋습니다.If a Bookmark Lookup WITH PREFETCH clause is causing the escalation, consider adding additional columns to the nonclustered index that appears in the Index Seek or the Index Scan logical operator below the Bookmark Lookup logical operator in the query plan. 포함 인덱스(쿼리에 사용된 테이블의 모든 열을 포함하는 인덱스) 또는 조인 조건이나 WHERE 절(선택 열 목록에 모든 것을 포함하는 것이 불가능한 경우)에 사용된 열을 포함하는 인덱스를 만들 수 있습니다.It may be possible to create a covering index (an index that includes all columns in a table that were used in the query), or at least an index that covers the columns that were used for join criteria or in the WHERE clause if including everything in the select column list is impractical. 중첩 루프 조인은 PREFETCH를 사용할 수도 있으며, 이로 인해 동일한 잠금 동작이 발생합니다.A Nested Loop join may also use PREFETCH, and this causes the same locking behavior.

  • 다른 SPID가 호환되지 않는 테이블 잠금을 보유하고 있는 경우 잠금 에스컬레이션이 발생할 수 없습니다.Lock escalation cannot occur if a different SPID is currently holding an incompatible table lock. 잠금 에스컬레이션은 항상 테이블 잠금으로 에스컬레이션되지만 페이지 잠금으로는 에스컬레이션되지 않습니다.Lock escalation always escalates to a table lock, and never to page locks. 추가로 다른 SPID에 호환되지 않은 TAB 잠금이 있어 잠금 에스컬레이션 시도가 실패하는 경우 에스컬레이션을 시도하는 쿼리가 TAB 잠금을 대기하는 동안 차단하지 않습니다.Additionally, if a lock escalation attempt fails because another SPID holds an incompatible TAB lock, the query that attempted escalation does not block while waiting for a TAB lock. 대신 더욱 세분화된 수준(행, 키 또는 페이지)에서 계속 잠금을 획득하여 주기적으로 에스컬레이션을 시도합니다.Instead, it continues to acquire locks at its original, more granular level (row, key, or page), periodically making additional escalation attempts. 따라서 특정 테이블에 대한 잠금 에스컬레이션을 방지하는 한 가지 방법은 에스컬레이션된 잠금 유형과 호환되지 않는 다른 연결에 대한 잠금을 획득하고 유지하는 것입니다.Therefore, one method to prevent lock escalation on a particular table is to acquire and to hold a lock on a different connection that is not compatible with the escalated lock type. 테이블 수준에서 IX(의도 배타) 잠금은 행 또는 페이지를 잠그지 않지만 에스컬레이션된 S(공유) 또는 X(배타) TAB 잠금과 호환되지 않습니다.An IX (intent exclusive) lock at the table level does not lock any rows or pages, but it is still not compatible with an escalated S (shared) or X (exclusive) TAB lock. 예를 들어 mytable 테이블에서 다수의 행을 수정하고 잠금 에스컬레이션으로 인해 발생하는 차단을 유발한 일괄 작업을 실행해야 한다고 가정합니다.For example, assume that you must run a batch job that modifies a large number of rows in the mytable table and that has caused blocking that occurs because of lock escalation. 이 작업이 항상 1시간 이내에 완료되는 경우 다음 코드를 포함하는 Transact-SQLTransact-SQL 작업을 만들고, 일괄 작업의 시작 시간 몇 분 전에 시작되도록 새 작업을 예약할 수 있습니다.If this job always completes in less than an hour, you might create a Transact-SQLTransact-SQL job that contains the following code, and schedule the new job to start several minutes before the batch job's start time:

    BEGIN TRAN
    SELECT * FROM mytable (UPDLOCK, HOLDLOCK) WHERE 1=0
    WAITFOR DELAY '1:00:00'
    COMMIT TRAN
    

    이 쿼리는 1시간 동안 mytable에 대한 IX 잠금을 획득 및 유지하고, 이로 인해 이 시간 동안 테이블에 대한 잠금 에스컬레이션이 방지됩니다.This query acquires and holds an IX lock on mytable for one hour, which prevents lock escalation on the table during that time. 이 일괄 처리는 데이터를 수정하거나 다른 쿼리를 차단하지 않습니다(다른 쿼리에서 TABLOCK 힌트를 사용한 테이블 잠금을 적용하지 않는 경우 또는 관리자가 sp_indexoption 저장 프로시저를 사용하여 페이지 또는 행 잠금을 사용하지 않도록 설정한 경우).This batch does not modify any data or block other queries (unless the other query forces a table lock with the TABLOCK hint or if an administrator has disabled page or row locks by using an sp_indexoption stored procedure).

추적 플래그 1211 및 1224를 사용하여 잠금 에스컬레이션의 전부 또는 일부를 해제할 수도 있습니다.You can also use trace flags 1211 and 1224 to disable all or some lock escalations. 하지만 추적 플래그는 전체 데이터베이스 엔진Database Engine에 대해 전역으로 모든 잠금 에스컬레이션을 사용하지 않도록 설정합니다.However, these trace flags disable all lock escalation globally for the entire 데이터베이스 엔진Database Engine. 잠금 에스컬레이션은 수천 개의 잠금을 획득하고 해제하는 오버헤드로 인해 저하되는 쿼리의 효율성을 극대화하여 데이터베이스 엔진Database Engine에서 매우 유용한 용도로 사용됩니다.Lock escalation serves a very useful purpose in the 데이터베이스 엔진Database Engine by maximizing the efficiency of queries that are otherwise slowed down by the overhead of acquiring and releasing several thousands of locks. 잠금 에스컬레이션은 잠금을 추적하는 데 필요한 메모리를 최소화하는 경우에도 도움이 됩니다.Lock escalation also helps to minimize the required memory to keep track of locks. 데이터베이스 엔진Database Engine에서 잠금 구조에 대해 동적으로 할당할 수 있는 메모리는 유한하므로 잠금 에스컬레이션을 사용하지 않도록 설정하고 잠금 메모리가 충분히 커지면 모든 쿼리에 대한 추가 잠금 할당 시도가 실패할 수 있으며 다음 오류가 발생합니다.The memory that the 데이터베이스 엔진Database Engine can dynamically allocate for lock structures is finite, so if you disable lock escalation and the lock memory grows large enough, attempts to allocate additional locks for any query may fail and the following error occurs:

The SQL Server cannot obtain a LOCK resource at this time. Rerun your statement when there are fewer active users or ask the system administrator to check the SQL Server lock and memory configuration.

참고

오류 1204가 발생하면 현재 문의 처리를 중지하고 활성 트랜잭션 롤백을 유발합니다.When error 1204 occurs, it stops the processing of the current statement and causes a rollback of the active transaction. 데이터베이스 서비스를 다시 시작하는 경우 롤백 자체가 사용자를 차단하거나 데이터베이스 복구 시간이 길어질 수 있습니다.The rollback itself may block users or lead to a long database recovery time if you restart the database service.

참고

ROWLOCK과 같은 잠금 힌트를 사용하면 초기 잠금 계획만 변경됩니다.Using a lock hint such as ROWLOCK only alters the initial lock plan. 잠금 힌트는 잠금 에스컬레이션을 방지하지 않습니다.Lock hints do not prevent lock escalation.

또한 다음 예제와 같이 lock_escalation xEvent(확장 이벤트)를 사용하여 잠금 에스컬레이션을 모니터링합니다.Also, monitor lock escalation by using the lock_escalation Extended Event (xEvent), such as in the following example:

-- Session creates a histogram of the number of lock escalations per database 
CREATE EVENT SESSION [Track_lock_escalation] ON SERVER 
ADD EVENT sqlserver.lock_escalation(SET collect_database_name=(1),collect_statement=(1)
    ACTION(sqlserver.database_id,sqlserver.database_name,sqlserver.query_hash_signed,sqlserver.query_plan_hash_signed,sqlserver.sql_text,sqlserver.username))
ADD TARGET package0.histogram(SET source=N'sqlserver.database_id')
GO

중요

SQL 추적 또는 SQL 프로파일러의 Lock:Escalation 이벤트 클래스 대신 lock_escalation xEvent(확장 이벤트)를 사용해야 합니다.The lock_escalation Extended Event (xEvent) should be used instead of the Lock:Escalation event class in SQL Trace or SQL Profiler

동적 잠금Dynamic Locking

행 잠금과 같이 낮은 수준의 잠금을 사용하면 두 트랜잭션이 동일한 데이터에 대해 동시에 잠금을 요청할 확률이 줄어들어 동시성이 증가합니다.Using low-level locks, such as row locks, increases concurrency by decreasing the probability that two transactions will request locks on the same piece of data at the same time. 또한 잠금 수 및 잠금 관리에 필요한 리소스 수도 늘어납니다.Using low-level locks also increases the number of locks and the resources needed to manage them. 테이블 또는 페이지 잠금과 같이 높은 수준의 잠금을 사용하면 오버헤드는 줄어들지만 동시성이 감소합니다.Using high-level table or page locks lowers overhead, but at the expense of lowering concurrency.

잠금 비용 대 동시성 비용

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 동적 잠금 전략을 사용하여 가장 비용 효율적인 잠금을 결정합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses a dynamic locking strategy to determine the most cost-effective locks. SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 스키마 및 쿼리의 특징을 기준으로 쿼리를 실행할 때 가장 적합한 잠금을 자동으로 결정합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine automatically determines what locks are most appropriate when the query is executed, based on the characteristics of the schema and query. 예를 들어 잠금 오버헤드를 줄이기 위해서 인덱스 검색을 수행할 때 최적화 프로그램이 인덱스에서 페이지 수준 잠금을 선택할 수 있습니다.For example, to reduce the overhead of locking, the optimizer may choose page-level locks in an index when performing an index scan.

동적 잠금을 사용하면 다음과 같은 장점이 있습니다.Dynamic locking has the following advantages:

  • 데이터베이스 관리가 간단해집니다.Simplified database administration. 데이터베이스 관리자가 잠금 에스컬레이션 임계값을 조정할 필요가 없습니다.Database administrators do not have to adjust lock escalation thresholds.
  • 성능이 향상됩니다.Increased performance. SQL Server 데이터베이스 엔진SQL Server Database Engine에서 태스크에 적합한 잠금을 사용하므로 시스템 오버헤드가 줄어듭니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine minimizes system overhead by using locks appropriate to the task.
  • 애플리케이션 개발자가 개발에만 전념할 수 있습니다.Application developers can concentrate on development. SQL Server 데이터베이스 엔진SQL Server Database Engine에서 잠금을 자동으로 조정합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine adjusts locking automatically.

SQL Server 2008SQL Server 2008부터 LOCK_ESCALATION 옵션이 도입되어 잠금 에스컬레이션 동작이 변경되었습니다.Starting with SQL Server 2008SQL Server 2008, the behavior of lock escalation has changed with the introduction of the LOCK_ESCALATION option. 자세한 내용은 ALTER TABLELOCK_ESCALATION 옵션을 참조하세요.For more information, see the LOCK_ESCALATION option of ALTER TABLE.

교착 상태Deadlocks

한 태스크에서 잠근 리소스를 다른 태스크에서 잠그려고 하여 둘 이상의 태스크가 서로 영구적으로 차단하면 교착 상태가 발생합니다.A deadlock occurs when two or more tasks permanently block each other by each task having a lock on a resource which the other tasks are trying to lock. 예를 들면 다음과 같습니다.For example:

  • 트랜잭션 A가 1행에 대한 공유 잠금을 획득합니다.Transaction A acquires a shared lock on row 1.
  • 트랜잭션 B가 2행에 대한 공유 잠금을 획득합니다.Transaction B acquires a shared lock on row 2.
  • 이제 트랜잭션 A가 2행에 대한 배타적 잠금을 요청하고 트랜잭션 B가 2행에 대해 소유하고 있는 공유 잠금을 종료 및 해제할 때까지 트랜잭션 A가 차단됩니다.Transaction A now requests an exclusive lock on row 2, and is blocked until transaction B finishes and releases the shared lock it has on row 2.
  • 이제 트랜잭션 B가 1행에 대한 배타적 잠금을 요청하고 트랜잭션 A가 1행에 대해 소유하고 있는 공유 잠금을 종료 및 해제할 때까지 트랜잭션 B가 차단됩니다.Transaction B now requests an exclusive lock on row 1, and is blocked until transaction A finishes and releases the shared lock it has on row 1.

트랜잭션 B가 완료되어야 트랜잭션 A도 완료될 수 있지만 트랜잭션 B는 트랜잭션 A에 의해 차단된 상태입니다. 이러한 상태를 순환 종속 관계라고 합니다. 트랜잭션 A는 트랜잭션 B에 종속되고 트랜잭션 B는 트랜잭션 A에 종속된 형태로 순환됩니다.Transaction A cannot complete until transaction B completes, but transaction B is blocked by transaction A. This condition is also called a cyclic dependency: Transaction A has a dependency on transaction B, and transaction B closes the circle by having a dependency on transaction A.

교착 상태의 트랜잭션은 둘 다 외부 프로세스에서 교착 상태를 해제할 때까지 기다립니다.Both transactions in a deadlock will wait forever unless the deadlock is broken by an external process. SQL Server 데이터베이스 엔진SQL Server Database Engine 교착 상태 모니터는 교착 상태에 있는 태스크가 있는지 주기적으로 검사합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine deadlock monitor periodically checks for tasks that are in a deadlock. 순환 종속 관계가 발견되면 모니터는 두 작업 중 처리하지 않을 태스크를 하나 선택하고 해당 트랜잭션을 오류와 함께 종료합니다.If the monitor detects a cyclic dependency, it chooses one of the tasks as a victim and terminates its transaction with an error. 이렇게 하여 다른 태스크가 해당 트랜잭션을 완료할 수 있습니다.This allows the other task to complete its transaction. 오류와 함께 종료된 트랜잭션의 애플리케이션은 해당 트랜잭션을 다시 시도하며 이 트랜잭션은 대개 교착 상태의 다른 트랜잭션이 완료된 후에 끝납니다.The application with the transaction that terminated with an error can retry the transaction, which usually completes after the other deadlocked transaction has finished.

교착 상태는 종종 일반적인 차단과 혼동됩니다.Deadlocking is often confused with normal blocking. 트랜잭션이 다른 트랜잭션에서 잠근 리소스에 대한 잠금을 요청하면 잠금이 해제될 때까지 잠금을 요청한 트랜잭션이 기다립니다.When a transaction requests a lock on a resource locked by another transaction, the requesting transaction waits until the lock is released. 기본적으로 LOCK_TIMEOUT이 설정되지 않은 한 SQL ServerSQL Server 트랜잭션 시간은 제한되지 않습니다.By default, SQL ServerSQL Server transactions do not time out, unless LOCK_TIMEOUT is set. 잠금을 요청하는 트랜잭션은 잠금을 소유하는 트랜잭션을 차단하기 위한 작업을 수행하지 않으므로 교착 상태에 빠지지 않고 차단됩니다.The requesting transaction is blocked, not deadlocked, because the requesting transaction has not done anything to block the transaction owning the lock. 결국 잠금을 소유하는 트랜잭션이 완료되고 잠금을 해제하면 잠금을 요청하는 트랜잭션에 잠금이 허가되고 트랜잭션이 진행됩니다.Eventually, the owning transaction will complete and release the lock, and then the requesting transaction will be granted the lock and proceed.

참고

교착 상태는 deadly embrace(치명적인 포옹)라고도 합니다.Deadlocks are sometimes called a deadly embrace.

교착 상태는 관계형 데이터베이스 관리 시스템뿐만 아니라 다중 스레드를 사용하는 어느 시스템에서나 발생할 수 있으며 데이터베이스 개체에 대한 잠금 이외의 리소스에 대해 발생할 수 있습니다.Deadlock is a condition that can occur on any system with multiple threads, not just on a relational database management system, and can occur for resources other than locks on database objects. 예를 들어 다중 스레드 운영 체제의 스레드는 메모리 블록과 같은 하나 이상의 리소스를 획득할 수 있습니다.For example, a thread in a multithreaded operating system might acquire one or more resources, such as blocks of memory. 획득하려는 리소스를 현재 다른 스레드가 소유하고 있으면 대상 리소스가 해제될 때까지 첫 번째 스레드가 기다려야 할 수 있습니다.If the resource being acquired is currently owned by another thread, the first thread may have to wait for the owning thread to release the target resource. 이렇게 대기 중인 스레드는 해당 리소스에 대해 리소스를 소유하는 스레드에 종속됩니다.The waiting thread is said to have a dependency on the owning thread for that particular resource. SQL Server 데이터베이스 엔진SQL Server Database Engine의 인스턴스에서 세션은 메모리나 스레드 등의 데이터베이스가 아닌 리소스를 획득할 때 교착 상태에 빠질 수 있습니다.In an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine, sessions can deadlock when acquiring nondatabase resources, such as memory or threads.

트랜잭션 교착 상태를 보여 주는 다이어그램

이 그림에서 트랜잭션 T1은 Part 테이블 잠금 리소스에 대해 트랜잭션 T2에 종속됩니다.In the illustration, transaction T1 has a dependency on transaction T2 for the Part table lock resource. 마찬가지로 스레드 T2는 Supplier 테이블 잠금 리소스에 대해 트랜잭션 T1에 종속됩니다.Similarly, transaction T2 has a dependency on transaction T1 for the Supplier table lock resource. 이러한 종속 관계는 순환적이므로 스레드 T1과 T2 간에 교착 상태가 발생합니다.Because these dependencies form a cycle, there is a deadlock between transactions T1 and T2.

테이블이 분할되고 ALTER TABLELOCK_ESCALATION 설정이 AUTO로 설정된 경우에도 교착 상태가 발생할 수 있습니다.Deadlocks can also occur when a table is partitioned and the LOCK_ESCALATION setting of ALTER TABLE is set to AUTO. LOCK_ESCALATION이 AUTO로 설정되면 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 TABLE 수준이 아니라 HoBT 수준에서 테이블 파티션을 잠그도록 허용하여 동시성이 증가합니다.When LOCK_ESCALATION is set to AUTO, concurrency increases by allowing the SQL Server 데이터베이스 엔진SQL Server Database Engine to lock table partitions at the HoBT level instead of at the table level. 그러나 개별 트랜잭션이 테이블에 파티션 잠금을 보유하고 다른 트랜잭션 파티션에서 잠금을 원하면 교착 상태가 발생합니다.However, when separate transactions hold partition locks in a table and want a lock somewhere on the other transactions partition, this causes a deadlock. 이런 유형의 교착 상태는 LOCK_ESCALATIONTABLE로 설정하면 방지할 수 있습니다. 하지만 이 설정으로 인해 테이블 잠금을 기다리도록 파티션에 대규모 업데이트가 강제 적용되어 동시성이 감소됩니다.This type of deadlock can be avoided by setting LOCK_ESCALATION to TABLE; although this setting will reduce concurrency by forcing large updates to a partition to wait for a table lock.

교착 상태 검색 및 종료Detecting and Ending Deadlocks

한 태스크에서 잠근 리소스를 다른 태스크에서 잠그려고 하여 둘 이상의 태스크가 서로 영구적으로 차단하면 교착 상태가 발생합니다.A deadlock occurs when two or more tasks permanently block each other by each task having a lock on a resource which the other tasks are trying to lock. 다음 그래프에서는 아래와 같은 교착 상태를 개괄적으로 보여 줍니다.The following graph presents a high level view of a deadlock state where:

  • 태스크 T1이 리소스 R1에 대한 잠금을 가지고 있고(R1에서 T1 방향의 화살표로 표시) 리소스 R2에 대한 잠금을 요청합니다(T1에서 R2 방향의 화살표로 표시).Task T1 has a lock on resource R1 (indicated by the arrow from R1 to T1) and has requested a lock on resource R2 (indicated by the arrow from T1 to R2).
  • 태스크 T2가 리소스 R2에 대한 잠금을 가지고 있고(R2에서 T2 방향의 화살표로 표시) 리소스 R1에 대한 잠금을 요청합니다(T2에서 R1 방향의 화살표로 표시).Task T2 has a lock on resource R2 (indicated by the arrow from R2 to T2) and has requested a lock on resource R1 (indicated by the arrow from T2 to R1).
  • 리소스가 사용 가능한 상태가 되어야 태스크를 계속할 수 있고 태스크가 계속되어야 리소스를 해제할 수 있으므로 교착 상태가 발생합니다.Because neither task can continue until a resource is available and neither resource can be released until a task continues, a deadlock state exists.

교착 상태에 있는 태스크를 보여 주는 다이어그램

SQL Server 데이터베이스 엔진SQL Server Database EngineSQL ServerSQL Server에서 교착 상태 순환을 자동으로 검색합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine automatically detects deadlock cycles within SQL ServerSQL Server. 그런 다음 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 교착 상태에 있는 세션 중 처리하지 않을 세션을 하나 선택하면 현재 트랜잭션이 오류와 함께 종료되면서 교착 상태가 해제됩니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine chooses one of the sessions as a deadlock victim and the current transaction is terminated with an error to break the deadlock.

교착 상태를 일으킬 수 있는 리소스Resources that can Deadlock

사용자 세션마다 세션을 위해 실행 중인 태스크가 하나 이상 있고 각 태스크는 다양한 리소스를 획득하거나 획득 대기 중일 수 있습니다.Each user session might have one or more tasks running on its behalf where each task might acquire or wait to acquire a variety of resources. 다음 유형의 리소스가 차단을 일으켜 교착 상태가 발생할 수 있습니다.The following types of resources can cause blocking that could result in a deadlock.

  • 잠금.Locks. 개체, 페이지, 행, 메타데이터, 애플리케이션 등의 리소스에 대한 잠금을 획득하려고 대기할 때 교착 상태가 발생할 수 있습니다.Waiting to acquire locks on resources, such as objects, pages, rows, metadata, and applications can cause deadlock. 예를 들어 트랜잭션 T1이 r1 행에 대한 공유(S) 잠금을 가지고 있고 r2에 대한 배타적(X) 잠금을 얻으려고 대기 중입니다.For example, transaction T1 has a shared (S) lock on row r1 and is waiting to get an exclusive (X) lock on r2. 트랜잭션 T2가 r2에 대한 공유(S) 잠금을 가지고 있고 r1 행에 대한 배타적(X) 잠금을 얻으려고 대기 중입니다.Transaction T2 has a shared (S) lock on r2 and is waiting to get an exclusive (X) lock on row r1. 이 경우 T1과 T2가 서로 잠근 리소스를 해제할 때까지 대기하는 잠금 순환이 발생합니다.This results in a lock cycle in which T1 and T2 wait for each other to release the locked resources.

  • 작업자 스레드.Worker threads. 사용 가능한 작업자 스레드를 대기하는 태스크가 교착 상태를 일으킬 수 있습니다.A queued task waiting for an available worker thread can cause deadlock. 대기 태스크가 모든 작업자 스레드를 차단하는 리소스를 소유하는 경우 교착 상태가 발생합니다.If the queued task owns resources that are blocking all worker threads, a deadlock will result. 예를 들어 세션 S1이 트랜잭션을 시작하고 r1 행에 대한 공유(S) 잠금을 획득한 후 중지됩니다.For example, session S1 starts a transaction and acquires a shared (S) lock on row r1 and then goes to sleep. 사용 가능한 모든 작업자 스레드에서 실행 중인 활성 세션이 r1 행에 대한 배타적(X) 잠금을 획득하려고 합니다.Active sessions running on all available worker threads are trying to acquire exclusive (X) locks on row r1. 세션 S1이 작업자 스레드를 획득할 수 없으므로 트랜잭션을 커밋할 수 없고 r1 행에 대한 잠금을 해제하지 못합니다.Because session S1 cannot acquire a worker thread, it cannot commit the transaction and release the lock on row r1. 이로 인해 교착 상태가 발생합니다.This results in a deadlock.

  • 메모리.Memory. 동시 요청이 사용 가능한 메모리보다 많은 메모리 부여를 대기하는 경우 교착 상태가 발생할 수 있습니다.When concurrent requests are waiting for memory grants that cannot be satisfied with the available memory, a deadlock can occur. 예를 들어 두 개의 동시 쿼리 Q1과 Q2가 각각 10MB와 20MB의 메모리를 획득하는 사용자 정의 함수를 실행합니다.For example, two concurrent queries, Q1 and Q2, execute as user-defined functions that acquire 10MB and 20MB of memory respectively. 각 쿼리에 30MB가 필요하고 사용 가능한 총 메모리는 20MB인 경우 Q1과 Q2는 서로 메모리를 해제할 때까지 대기해야 하며 이로 인해 교착 상태가 발생합니다.If each query needs 30MB and the total available memory is 20MB, then Q1 and Q2 must wait for each other to release memory, and this results in a deadlock.

  • 병렬 쿼리 실행 관련 리소스.Parallel query execution-related resources. 일반적으로 교환 포트와 관련된 코디네이터, 생산자 및 소비자 스레드가 병렬 쿼리에 속하지 않는 하나 이상의 다른 프로세스를 포함하는 경우 서로 차단하여 교착 상태가 발생할 수 있습니다.Coordinator, producer, or consumer threads associated with an exchange port may block each other causing a deadlock usually when including at least one other process that is not a part of the parallel query. 또한 병렬 쿼리 실행을 시작할 때 SQL ServerSQL Server는 현재 작업을 기반으로 병렬 처리 수준, 즉 작업자 스레드 수를 결정합니다.Also, when a parallel query starts execution, SQL ServerSQL Server determines the degree of parallelism, or the number of worker threads, based upon the current workload. 예를 들어 서버에서 새 쿼리 실행이 시작되거나 시스템에 작업자 스레드가 부족하여 시스템 작업이 예기치 않게 변경되면 교착 상태가 발생할 수 있습니다.If the system workload unexpectedly changes, for example, where new queries start running on the server or the system runs out of worker threads, then a deadlock could occur.

  • MARS(Multiple Active Result Sets) 리소스.Multiple Active Result Sets (MARS) resources. MARS 리소스는 MARS에서 여러 활성 요청의 인터리브를 제어하는 데 사용합니다.These resources are used to control interleaving of multiple active requests under MARS. 자세한 내용은 MARS(Multiple Active Result Sets) 사용을 참조하세요.For more information, see Using Multiple Active Result Sets (MARS).

    • 사용자 리소스.User resource. 스레드가 사용자 애플리케이션에서 제어하는 리소스를 대기할 때 해당 리소스는 외부 또는 사용자 리소스로 간주되고 잠금처럼 처리됩니다.When a thread is waiting for a resource that is potentially controlled by a user application, the resource is considered to be an external or user resource and is treated like a lock.

    • 세션 뮤텍스.Session mutex. 한 세션에서 실행되고 있는 태스크가 인터리브됩니다. 이는 세션에서 한 태스크만 실행할 수 있음을 나타냅니다.The tasks running in one session are interleaved, meaning that only one task can run under the session at a given time. 세션 뮤텍스를 배타적으로 사용할 수 있어야 태스크가 실행될 수 있습니다.Before the task can run, it must have exclusive access to the session mutex.

    • 트랜잭션 뮤텍스.Transaction mutex. 한 트랜잭션에서 실행되고 있는 가 인터리브됩니다. 이는 트랜잭션에서 한 태스크만 실행할 수 있음을 나타냅니다.All tasks running in one transaction are interleaved, meaning that only one task can run under the transaction at a given time. 트랜잭션 뮤텍스를 배타적으로 사용할 수 있어야 태스크가 실행될 수 있습니다.Before the task can run, it must have exclusive access to the transaction mutex.

    MARS에서 태스크가 빠르게 실행되려면 태스크가 세션 뮤텍스를 획득해야 합니다.In order for a task to run under MARS, it must acquire the session mutex. 태스크가 트랜잭션에서 실행되고 있는 경우에는 트랜잭션 뮤텍스를 획득해야 합니다.If the task is running under a transaction, it must then acquire the transaction mutex. 이를 통해 지정된 세션과 지정된 트랜잭션에서 한 번에 한 태스크만 활성화되도록 할 수 있습니다.This guarantees that only one task is active at one time in a given session and a given transaction. 필요한 뮤텍스가 획득되면 태스크가 실행될 수 있습니다.Once the required mutexes have been acquired, the task can execute. 태스크가 완료되거나 요청 중간에 취소되면 태스크는 뮤텍스를 획득할 때와는 반대의 순서로 먼저 트랜잭션 뮤텍스를 해제하고 세션 뮤텍스를 해제합니다.When the task finishes, or yields in the middle of the request, it will first release transaction mutex followed by the session mutex in reverse order of acquisition. 그러나 이러한 리소스에서 교착 상태가 발생할 수 있습니다.However, deadlocks can occur with these resources. 다음 코드 예제에서는 사용자 요청 U1과 사용자 요청 U2라는 두 태스크가 같은 세션에서 실행되고 있습니다.In the following code example, two tasks, user request U1 and user request U2, are running in the same session.

    U1:    Rs1=Command1.Execute("insert sometable EXEC usp_someproc");  
    U2:    Rs2=Command2.Execute("select colA from sometable");  
    

    사용자 요청 U1에서 실행되는 저장 프로시저가 세션 뮤텍스를 획득합니다.The stored procedure executing from user request U1 has acquired the session mutex. 저장 프로시저를 실행하는 데 시간이 오래 걸리면 SQL Server 데이터베이스 엔진SQL Server Database Engine은 저장 프로시저가 사용자 입력을 대기하고 있는 것으로 간주합니다.If the stored procedure takes a long time to execute, it is assumed by the SQL Server 데이터베이스 엔진SQL Server Database Engine that the stored procedure is waiting for input from the user. 사용자가 사용자 요청 U2의 결과 집합을 대기하는 동안 U2는 세션 뮤텍스를 대기하고 U1은 사용자 리소스를 대기합니다.User request U2 is waiting for the session mutex while the user is waiting for the result set from U2, and U1 is waiting for a user resource. 다음 그림에서는 이 교착 상태를 논리적으로 보여 줍니다.This is deadlock state logically illustrated as:

LogicFlowExamplec

교착 상태 검색Deadlock Detection

위의 섹션에서 나열한 리소스는 모두 SQL Server 데이터베이스 엔진SQL Server Database Engine 교착 상태 검색 스키마에 포함됩니다.All of the resources listed in the section above participate in the SQL Server 데이터베이스 엔진SQL Server Database Engine deadlock detection scheme. 교착 상태 검색은 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스의 모든 태스크에 대한 검색을 주기적으로 시작하는 잠금 모니터에서 수행합니다.Deadlock detection is performed by a lock monitor thread that periodically initiates a search through all of the tasks in an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine. 다음은 검색 프로세스에 대한 설명입니다.The following points describe the search process:

  • 기본 간격은 5초입니다.The default interval is 5 seconds.
  • 잠금 모니터 스레드가 교착 상태를 발견하면 잠금 상태의 빈도에 따라 5초에서 최하 100밀리초까지 교착 상태 검색 간격이 짧아집니다.If the lock monitor thread finds deadlocks, the deadlock detection interval will drop from 5 seconds to as low as 100 milliseconds depending on the frequency of deadlocks.
  • 잠금 모니터 스레드가 교착 상태 검색을 중지하면 SQL Server 데이터베이스 엔진SQL Server Database Engine은 검색 간격을 5초로 늘립니다.If the lock monitor thread stops finding deadlocks, the SQL Server 데이터베이스 엔진SQL Server Database Engine increases the intervals between searches to 5 seconds.
  • 교착 상태가 검색되면 잠금을 대기해야 하는 다음 스레드가 교착 상태 순환에 들어가는 것으로 간주됩니다.If a deadlock has just been detected, it is assumed that the next threads that must wait for a lock are entering the deadlock cycle. 교착 상태 검색 후 처음 두 번의 잠금 대기에서 다음 교착 상태 검색 간격을 대기하지 않고 교착 상태 검색을 즉시 트리거합니다.The first couple of lock waits after a deadlock has been detected will immediately trigger a deadlock search rather than wait for the next deadlock detection interval. 예를 들어 현재 간격이 5초일 경우 교착 상태가 검색되면 다음 잠금 대기에서 교착 상태 검색기를 즉시 시작합니다.For example, if the current interval is 5 seconds, and a deadlock was just detected, the next lock wait will kick off the deadlock detector immediately. 교착 상태에 속할 경우 이 잠금 대기는 다음 교착 상태 검색 전에 바로 검색됩니다.If this lock wait is part of a deadlock, it will be detected right away rather than during next deadlock search.

일반적으로 SQL Server 데이터베이스 엔진SQL Server Database Engine은 주기적인 교착 상태 검색만 수행합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine typically performs periodic deadlock detection only. 시스템에서 발생하는 교착 상태 수는 대개 적으므로 주기적인 교착 상태 검색을 통해 시스템의 교착 상태 검색 오버헤드를 줄일 수 있습니다.Because the number of deadlocks encountered in the system is usually small, periodic deadlock detection helps to reduce the overhead of deadlock detection in the system.

특정 스레드에 대해 교착 상태 검색을 시작할 때 잠금 모니터는 스레드가 대기하고 있는 리소스를 확인합니다.When the lock monitor initiates deadlock search for a particular thread, it identifies the resource on which the thread is waiting. 그런 다음 잠금 모니터는 해당 리소스의 소유자를 찾은 후 순환을 발견할 때까지 이러한 스레드에 대한 교착 상태 검색을 반복적으로 수행합니다.The lock monitor then finds the owner(s) for that particular resource and recursively continues the deadlock search for those threads until it finds a cycle. 이러한 방법을 통해 확인된 순환으로 교착 상태가 일어납니다.A cycle identified in this manner forms a deadlock.

교착 상태가 검색되면 SQL Server 데이터베이스 엔진SQL Server Database Engine은 교착 상태에 있는 스레드 중 처리하지 않을 스레드를 하나 선택하여 교착 상태를 끝냅니다.After a deadlock is detected, the SQL Server 데이터베이스 엔진SQL Server Database Engine ends a deadlock by choosing one of the threads as a deadlock victim. SQL Server 데이터베이스 엔진SQL Server Database Engine은 스레드에 대해 실행되고 있는 현재 일괄 처리를 종료하고 해당 트랜잭션을 롤백한 후 애플리케이션에 1205 오류를 반환합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine terminates the current batch being executed for the thread, rolls back the transaction of the deadlock victim, and returns a 1205 error to the application. 처리하지 않도록 선택된 스레드의 트랜잭션이 롤백되면 이 트랜잭션에서 보유하는 모든 잠금이 해제됩니다.Rolling back the transaction for the deadlock victim releases all locks held by the transaction. 이를 통해 다른 스레드의 트랜잭션이 차단 해제되고 계속됩니다.This allows the transactions of the other threads to become unblocked and continue. 1205 교착 상태 미처리 오류는 교착 상태와 관련된 스레드와 리소스에 대한 정보를 오류 로그에 기록합니다.The 1205 deadlock victim error records information about the threads and resources involved in a deadlock in the error log.

기본적으로 SQL Server 데이터베이스 엔진SQL Server Database Engine은 롤백 비용이 가장 저렴한 트랜잭션을 실행하는 세션을 처리하지 않도록 선택합니다.By default, the SQL Server 데이터베이스 엔진SQL Server Database Engine chooses as the deadlock victim the session running the transaction that is least expensive to roll back. 또는 사용자가 SET DEADLOCK_PRIORITY 문을 사용하여 교착 상태에 있는 세션의 우선 순위를 지정할 수 있습니다.Alternatively, a user can specify the priority of sessions in a deadlock situation using the SET DEADLOCK_PRIORITY statement. DEADLOCK_PRIORITY를 LOW, NORMAL 또는 HIGH로 설정하거나 -10에서 10 사이의 정수 값으로 설정할 수 있습니다.DEADLOCK_PRIORITY can be set to LOW, NORMAL, or HIGH, or alternatively can be set to any integer value in the range (-10 to 10). 교착 상태 우선 순위는 기본적으로 NORMAL입니다.The deadlock priority defaults to NORMAL. 두 세션의 교착 상태 우선 순위가 다르면 교착 상태 우선 순위가 낮은 세션이 처리하지 않을 세션으로 선택됩니다.If two sessions have different deadlock priorities, the session with the lower priority is chosen as the deadlock victim. 두 세션의 교착 상태 우선 순위가 같으면 롤백 비용이 가장 저렴한 트랜잭션의 세션이 선택됩니다.If both sessions have the same deadlock priority, the session with the transaction that is least expensive to roll back is chosen. 교착 상태 순환과 관련된 세션의 교착 상태 우선 순위와 비용이 같으면 임의의 세션이 선택됩니다.If sessions involved in the deadlock cycle have the same deadlock priority and the same cost, a victim is chosen randomly.

CLR를 사용할 경우 교착 상태 모니터는 관리 프로시저 내부에서 액세스하는 모니터, 판독기/기록기 잠금, 스레드 조인 등의 동기화 리소스에 대한 교착 상태를 자동으로 검색합니다.When working with CLR, the deadlock monitor automatically detects deadlock for synchronization resources (monitors, reader/writer lock and thread join) accessed inside managed procedures. 그러나 처리하지 않도록 선택된 프로시저에서 예외가 발생하면 교착 상태가 해결됩니다.However, the deadlock is resolved by throwing an exception in the procedure that was selected to be the deadlock victim. 처리하지 않도록 선택된 프로시저에서 현재 소유하고 있는 리소스가 예외를 통해 자동으로 해제되지는 않습니다. 리소스는 명시적으로 해제해야 합니다.It is important to understand that the exception does not automatically release resources currently owned by the victim; the resources must be explicitly released. 예외 동작에 따라 처리하지 않도록 선택된 프로시저를 확인하는 데 사용되는 예외를 찾아 해제할 수 있습니다.Consistent with exception behavior, the exception used to identify a deadlock victim can be caught and dismissed.

교착 상태 정보 도구Deadlock Information Tools

교착 상태 정보를 표시하기 위해 SQL Server 데이터베이스 엔진SQL Server Database Engine은 SQL Profiler에서 교착 상태 그래프 이벤트와 두 개의 추적 플래그 system_health xEvent session 형식으로 모니터링 도구를 제공합니다.To view deadlock information, the SQL Server 데이터베이스 엔진SQL Server Database Engine provides monitoring tools in the form of the system_health xEvent session, two trace flags, and the deadlock graph event in SQL Profiler.

교착 상태 확장 이벤트Deadlock Extended Event

SQL Server 2012(11.x)SQL Server 2012 (11.x)부터 SQL 추적 또는 SQL Profiler의 교착 상태 그래프 이벤트 클래스 대신 xml_deadlock_report 확장 이벤트(xEvent)를 사용해야 합니다.Starting with SQL Server 2012(11.x)SQL Server 2012 (11.x), the xml_deadlock_report Extended Event (xEvent) should be used instead of the Deadlock graph event class in SQL Trace or SQL Profiler.

또한 SQL Server 2012(11.x)SQL Server 2012 (11.x) 이상에서는 교착 상태가 발생할 때 *system_health _ 세션이 이미 교착 상태 그래프가 포함된 xml_deadlock_report xEvent를 모두 캡처합니다.Also starting with SQL Server 2012(11.x)SQL Server 2012 (11.x), when deadlocks occur, the *system_health _ session already captures all xml_deadlock_report xEvents which contain the deadlock graph. _system_health* 세션은 기본적으로 사용되므로, 교착 상태 정보를 캡처하기 위해 별도의 xEvent 세션을 구성하지 않아도 됩니다.Because the _system_health* session is enabled by default, it's not required that a separate xEvent session is configured to capture deadlock information.

교착 상태 그래프에는 일반적으로 세 개의 서로 다른 노드가 있습니다.The deadlock graph captured typically has three distinct nodes:

  • victim-list.victim-list. 교착 상태 희생자 프로세스 식별자.The deadlock victim process identifier.
  • process-list.process-list. 교착 상태와 관련된 모든 프로세스에에 관한 정보입니다.Information on all the processes involved in the deadlock.
  • resource-list.resource-list. 교착 상태와 관련된 리소스에 관한 정보입니다.Information about the resources involved in the deadlock.

system_health 세션 파일 또는 링 버퍼를 열어 xml_deadlock_report xEvent가 기록되면 Management StudioManagement Studio는 다음 예에서 볼 수 있듯이 교착 상태와 관련된 작업과 리소스를 그래픽으로 표시합니다.Opening the system_health session file or ring buffer, if the xml_deadlock_report xEvent is recorded, Management StudioManagement Studio presents a graphical depiction of the tasks and resources involved in a deadlock, as seen in the following example:

xEvent 교착 상태 그래프

다음 쿼리는 system_health 세션 링 버퍼를 통해 캡처된 교착 상태 이벤트를 모두 표시할 수 있습니다.The following query can view all deadlock events captured by the system_health session ring buffer:

SELECT xdr.value('@timestamp', 'datetime') AS [Date],
    xdr.query('.') AS [Event_Data]
FROM (SELECT CAST([target_data] AS XML) AS Target_Data
            FROM sys.dm_xe_session_targets AS xt
            INNER JOIN sys.dm_xe_sessions AS xs ON xs.address = xt.event_session_address
            WHERE xs.name = N'system_health'
              AND xt.target_name = N'ring_buffer'
    ) AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr)
ORDER BY [Date] DESC

결과 집합은 다음과 같습니다.Here is the result set.

system_health_xevent_query_result

다음 예제는 위 결과의 첫 번째 링크를 클릭한 후 출력을 보여줍니다.The following example shows the output, after clicking on the first link of the result above:

<event name="xml_deadlock_report" package="sqlserver" timestamp="2018-02-18T08:26:24.698Z">
  <data name="xml_report">
    <type name="xml" package="package0" />
    <value>
      <deadlock>
        <victim-list>
          <victimProcess id="process27b9b0b9848" />
        </victim-list>
        <process-list>
          <process id="process27b9b0b9848" taskpriority="0" logused="0" waitresource="KEY: 5:72057594214350848 (1a39e6095155)" waittime="1631" ownerId="11088595" transactionname="SELECT" lasttranstarted="2018-02-18T00:26:23.073" XDES="0x27b9f79fac0" lockMode="S" schedulerid="9" kpid="15336" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2018-02-18T00:26:22.893" lastbatchcompleted="2018-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="7908" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088595" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2016CTP3.dbo.p1" line="3" stmtstart="78" stmtend="180" sqlhandle="0x0300050020766505ca3e07008ba8000001000000000000000000000000000000000000000000000000000000">
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x020000006263ec01ebb919c335024a072a2699958d3fcce60000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1) 
BEGIN
    EXEC p1 4
END
   </inputbuf>
          </process>
          <process id="process27b9ee33c28" taskpriority="0" logused="252" waitresource="KEY: 5:72057594214416384 (e5b3d7e750dd)" waittime="1631" ownerId="11088593" transactionname="UPDATE" lasttranstarted="2018-02-18T00:26:23.073" XDES="0x27ba15a4490" lockMode="X" schedulerid="6" kpid="5584" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-02-18T00:26:22.890" lastbatchcompleted="2018-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="15316" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088593" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2016CTP3.dbo.p2" line="3" stmtstart="76" stmtend="150" sqlhandle="0x03000500599a5906ce3e07008ba8000001000000000000000000000000000000000000000000000000000000">
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x02000000008fe521e5fb1099410048c5743ff7da04b2047b0000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1) 
BEGIN
    EXEC p2 4
END
   </inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057594214350848" dbid="5" objectname="AdventureWorks2016CTP3.dbo.t1" indexname="cidx" id="lock27b9dd26a00" mode="X" associatedObjectId="72057594214350848">
            <owner-list>
              <owner id="process27b9ee33c28" mode="X" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9b0b9848" mode="S" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594214416384" dbid="5" objectname="AdventureWorks2016CTP3.dbo.t1" indexname="idx1" id="lock27afa392600" mode="S" associatedObjectId="72057594214416384">
            <owner-list>
              <owner id="process27b9b0b9848" mode="S" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9ee33c28" mode="X" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </value>
  </data>
</event>

자세한 내용은 system_health 세션 사용을 참조하세요.For more information, see Use the system_health Session

추적 플래그 1204 및 추적 플래그 1222Trace Flag 1204 and Trace Flag 1222

교착 상태가 발생하면 추적 플래그 1204와 추적 플래그 1222는 SQL ServerSQL Server 오류 로그에 캡처된 정보를 반환합니다.When deadlocks occur, trace flag 1204 and trace flag 1222 return information that is captured in the SQL ServerSQL Server error log. 추적 플래그 1204는 교착 상태와 관련된 각 노드에 의해 형식이 지정된 교착 상태 정보를 보고합니다.Trace flag 1204 reports deadlock information formatted by each node involved in the deadlock. 추적 플래그 1222는 프로세스별 및 리소스별 순서로 교착 상태 정보의 형식을 지정합니다.Trace flag 1222 formats deadlock information, first by processes and then by resources. 두 추적 플래그에서 동일한 교착 상태 이벤트의 두 가지 표현을 가져오도록 설정할 수 있습니다.It is possible to enable both trace flags to obtain two representations of the same deadlock event.

중요

워크로드가 많고 교착 상태가 발생하는 시스템에서는 추적 플래그 1204와 1222를 사용하지 않는 것이 좋습니다.Avoid using trace flag 1204 and 1222 on workload-intensive systems that are causing deadlocks. 이러한 추적 플래그를 사용하면 성능 문제가 발생할 수 있습니다.Using these trace flags may introduce performance issues. 대신, 교착 상태 확장 이벤트(#deadlock_xevent)를 사용합니다.Instead, use the Deadlock Extended Event(#deadlock_xevent).

다음 표에서는 추적 플래그 1204 및 1222의 속성 정의 외에도 두 추적 플래그의 유사점과 차이점을 보여 줍니다.In addition to defining the properties of trace flag 1204 and 1222, the following table also shows the similarities and differences.

속성Property 추적 플래그 1204 및 추적 플래그 1222Trace Flag 1204 and Trace Flag 1222 추적 플래그 1204만 해당Trace Flag 1204 only 추적 플래그 1222만 해당Trace Flag 1222 only
출력 형식Output format SQL ServerSQL Server 오류 로그에 출력이 캡처됩니다.Output is captured in the SQL ServerSQL Server error log. 교착 상태와 관련된 노드에 초점을 둡니다.Focused on the nodes involved in the deadlock. 각 노드에 해당하는 섹션이 있으며 마지막 섹션에서 교착 상태에 대해 설명합니다.Each node has a dedicated section, and the final section describes the deadlock victim. XSD(XML 스키마 정의) 스키마를 따르지 않는 XML과 유사한 형식으로 정보를 반환합니다.Returns information in an XML-like format that does not conform to an XML Schema Definition (XSD) schema. 형식은 3가지 주요 섹션으로 이루어져 있습니다.The format has three major sections. 첫 번째 섹션에서는 교착 상태를 선언합니다.The first section declares the deadlock victim. 두 번째 섹션에서는 교착 상태와 관련된 각 프로세스에 대해 설명합니다.The second section describes each process involved in the deadlock. 세 번째 섹션에서는 추적 플래그 1204의 노드와 같은 리소스에 대해 설명합니다.The third section describes the resources that are synonymous with nodes in trace flag 1204.
식별 특성Identifying attributes SPID:<x> ECID:<x>.SPID:<x> ECID:<x>. 병렬 프로세스의 경우 시스템 프로세스 ID 스레드를 식별합니다.Identifies the system process ID thread in cases of parallel processes. SPID:<x> ECID:0 항목은 주 스레드를 나타냅니다. 여기서 <x>는 SPID 값으로 대체됩니다.The entry SPID:<x> ECID:0, where <x> is replaced by the SPID value, represents the main thread. SPID:<x> ECID:<y> 항목은 동일한 SPID의 하위 스레드를 나타냅니다. 여기서 <x>는 SPID 값으로 대체되고 <y>는 0보다 큽니다.The entry SPID:<x> ECID:<y>, where <x> is replaced by the SPID value and <y> is greater than 0, represents the sub-threads for the same SPID.

BatchID(추적 플래그 1222의 경우 sbid).BatchID (sbid for trace flag 1222). 잠금을 요청하거나 보유하고 있는 코드 실행이 속한 일괄 처리를 식별합니다.Identifies the batch from which code execution is requesting or holding a lock. MARS(Multiple Active Result Sets)가 해제되어 있으면 BatchID 값은 0입니다.When Multiple Active Result Sets (MARS) is disabled, the BatchID value is 0. MARS가 설정되어 있으면 활성 일괄 처리 값은 1에서 n 사이입니다.When MARS is enabled, the value for active batches is 1 to n. 세션에 활성 일괄 처리가 없는 경우 BatchID는 0입니다.If there are no active batches in the session, BatchID is 0.

모드.Mode. 스레드가 요청, 부여 또는 대기한 특정 리소스에 대한 잠금 유형을 지정합니다.Specifies the type of lock for a particular resource that is requested, granted, or waited on by a thread. Mode는 IS(내재된 공유), S(공유), U(업데이트), IX(의도 배타), SIX(의도 배타 공유) 및 X(배타)가 될 수 있습니다.Mode can be IS (Intent Shared), S (Shared), U (Update), IX (Intent Exclusive), SIX (Shared with Intent Exclusive), and X (Exclusive).

Line # (추적 플래그 1222의 경우 line).Line # (line for trace flag 1222). 현재 문 일괄 처리에서 교착 상태 발생 시 실행 중이었던 줄 번호를 나열합니다.Lists the line number in the current batch of statements that was being executed when the deadlock occurred.

Input Buf (추적 플래그 1222의 경우 inputbuf).Input Buf (inputbuf for trace flag 1222). 현재 일괄 처리에 있는 모든 문을 나열합니다.Lists all the statements in the current batch.
노드.Node. 교착 상태 체인에서 항목 번호를 나타냅니다.Represents the entry number in the deadlock chain.

목록.Lists. 잠금 소유자는 다음 목록에 포함될 수 있습니다.The lock owner can be part of these lists:

Grant List.Grant List. 리소스의 현재 소유자를 열거합니다.Enumerates the current owners of the resource.

Convert List.Convert List. 잠금을 더 높은 수준으로 변환 중인 현재 소유자를 열거합니다.Enumerates the current owners that are trying to convert their locks to a higher level.

Wait List.Wait List. 리소스에 대한 현재 새 잠금 요청을 열거합니다.Enumerates current new lock requests for the resource.

Statement Type.Statement Type. 스레드에 사용 권한이 있는 DML 문의 유형(SELECT, INSERT, UPDATE 또는 DELETE)에 대해 설명합니다.Describes the type of DML statement (SELECT, INSERT, UPDATE, or DELETE) on which the threads have permissions.

Victim Resource Owner.Victim Resource Owner. SQL ServerSQL Server에서 교착 상태 순환을 끊도록 선택되는 참여하는 스레드를 지정합니다.Specifies the participating thread that SQL ServerSQL Server chooses as the victim to break the deadlock cycle. 선택된 스레드와 기존의 모든 하위 스레드가 종료됩니다.The chosen thread and all existing sub-threads are terminated.

Next Branch.Next Branch. 교착 상태 순환과 관련된 동일한 SPID의 하위 스레드 두 개 이상을 나타냅니다.Represents the two or more sub-threads from the same SPID that are involved in the deadlock cycle.
deadlock victim.deadlock victim. 교착 상태에 있는 태스크 중 처리하지 않도록 선택된 태스크의 실제 메모리 주소를 나타냅니다. sys.dm_os_tasks(Transact-SQL)를 참조하십시오.Represents the physical memory address of the task (see sys.dm_os_tasks (Transact-SQL)) that was selected as a deadlock victim. 해결되지 않은 교착 상태의 경우 이 속성이 0일 수 있습니다.It may be 0 (zero) in the case of an unresolved deadlock. 롤백하고 있는 태스크를 처리하지 않도록 선택할 수는 없습니다.A task that is rolling back cannot be chosen as a deadlock victim.

executionstack.executionstack. 교착 상태 발생 시 실행 중인 Transact-SQLTransact-SQL 코드를 나타냅니다.Represents Transact-SQLTransact-SQL code that is being executed at the time the deadlock occurs.

priority.priority. 교착 상태 우선 순위를 나타냅니다.Represents deadlock priority. 특정 경우에 동시성 향상을 위해 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 잠시 교착 상태 우선 순위를 바꿀 수 있습니다.In certain cases, the SQL Server 데이터베이스 엔진SQL Server Database Engine may opt to alter the deadlock priority for a short duration to achieve better concurrency.

logused.logused. 태스크에서 사용하는 로그 공간입니다.Log space used by the task.

소유자 ID. 요청을 제어하는 트랜잭션의 ID입니다.owner id. The ID of the transaction that has control of the request.

상태.status. 태스크의 상태입니다.State of the task. 다음 값 중 하나입니다.It is one of the following values:

>> 보류 중.>> pending. 작업자 스레드 대기 중입니다.Waiting for a worker thread.

>> 실행 가능.>> runnable. 실행 준비가 완료되었지만 퀀텀 대기 중입니다.Ready to run but waiting for a quantum.

>> 실행.>> running. 현재 스케줄러에서 실행 중입니다.Currently running on the scheduler.

>> 일시 중지됨.>> suspended. 실행이 일시 중지되었습니다.Execution is suspended.

>> 완료.>> done. 태스크가 완료되었습니다.Task has completed.

>> spinloop.>> spinloop. spinlock이 사용 가능할 때까지 대기합니다.Waiting for a spinlock to become free.

waitresource.waitresource. 태스크에 필요한 리소스입니다.The resource needed by the task.

waittime.waittime. 리소스 대기 시간(밀리초)입니다.Time in milliseconds waiting for the resource.

schedulerid.schedulerid. 이 태스크와 관련된 스케줄러입니다.Scheduler associated with this task. sys.dm_os_schedulers(Transact-SQL) 참조.See sys.dm_os_schedulers (Transact-SQL).

hostname.hostname. 워크스테이션의 이름입니다.The name of the workstation.

isolationlevel.isolationlevel. 현재 트랜잭션 격리 수준입니다.The current transaction isolation level.

Xactid.Xactid. 요청을 제어하는 트랜잭션의 ID입니다.The ID of the transaction that has control of the request.

currentdb.currentdb. 데이터베이스의 ID입니다.The ID of the database.

lastbatchstarted.lastbatchstarted. 클라이언트 프로세스에서 일괄 처리 실행을 마지막으로 시작한 시간입니다.The last time a client process started batch execution.

lastbatchcompleted.lastbatchcompleted. 클라이언트 프로세스에서 일괄 처리 실행을 마지막으로 완료한 시간입니다.The last time a client process completed batch execution.

clientoption1 및 clientoption2.clientoption1 and clientoption2. 이 클라이언트 연결의 옵션을 설정합니다.Set options on this client connection. 대개 SET NOCOUNT와 SET XACTABORT 등의 SET 문으로 제어하는 옵션에 대한 정보가 포함된 비트 마스크입니다.This is a bitmask that includes information about options usually controlled by SET statements such as SET NOCOUNT and SET XACTABORT.

associatedObjectId.associatedObjectId. HoBT(힙 또는 B-트리) ID를 나타냅니다.Represents the HoBT (heap or b-tree) ID.
리소스 특성Resource attributes RID.RID. 잠금이 보유 또는 요청된 테이블 내의 단일 행을 식별합니다.Identifies the single row within a table on which a lock is held or requested. RID는 RID로 표시됩니다. db_id:file_id:page_no:row_no.RID is represented as RID: db_id:file_id:page_no:row_no. 예들 들어 RID: 6:1:20789:0입니다.For example, RID: 6:1:20789:0.

OBJECT.OBJECT. 잠금이 보유 또는 요청된 테이블을 식별합니다.Identifies the table on which a lock is held or requested. OBJECT는 OBJECT로 표시됩니다. db_id:object_id.OBJECT is represented as OBJECT: db_id:object_id. 예들 들어 TAB: 6:2009058193입니다.For example, TAB: 6:2009058193.

KEY.KEY. 잠금이 보유 또는 요청된 인덱스 내의 키 범위를 식별합니다.Identifies the key range within an index on which a lock is held or requested. KEY는 KEY로 표시됩니다. db_id:hobt_id (index key hash value).KEY is represented as KEY: db_id:hobt_id (index key hash value). 예들 들어 KEY: 6:72057594057457664 (350007a4d329)입니다.For example, KEY: 6:72057594057457664 (350007a4d329).

PAG.PAG. 잠금이 보유 또는 요청된 페이지 리소스를 식별합니다.Identifies the page resource on which a lock is held or requested. PAG는 PAG로 표시됩니다. db_id:file_id:page_no.PAG is represented as PAG: db_id:file_id:page_no. 예들 들어 PAG: 6:1:20789입니다.For example, PAG: 6:1:20789.

EXT.EXT. 익스텐트 구조를 식별합니다.Identifies the extent structure. EXT는 EXT로 표시됩니다. db_id:file_id:extent_no.EXT is represented as EXT: db_id:file_id:extent_no. 예들 들어 EXT: 6:1:9입니다.For example, EXT: 6:1:9.

DB.DB. 데이터베이스 잠금을 식별합니다.Identifies the database lock. DB는 다음 방법 중 하나로 표시됩니다.DB is represented in one of the following ways:

DB: db_idDB: db_id

DB: db_id[BULK-OP-DB]. 이 방법은 백업 데이터베이스에서 수행된 데이터베이스 잠금을 식별합니다.DB: db_id[BULK-OP-DB], which identifies the database lock taken by the backup database.

DB: db_id[BULK-OP-LOG]. 이 방법은 특정 데이터베이스에 대해 백업 로그에서 수행된 잠금을 식별합니다.DB: db_id[BULK-OP-LOG], which identifies the lock taken by the backup log for that particular database.

APP.APP. 애플리케이션 리소스에서 수행된 잠금을 식별합니다.Identifies the lock taken by an application resource. APP는 APP로 표시됩니다. lock_resource.APP is represented as APP: lock_resource. 예들 들어 APP: Formf370f478입니다.For example, APP: Formf370f478.

METADATA.METADATA. 교착 상태와 관련된 메타데이터 리소스를 나타냅니다.Represents metadata resources involved in a deadlock. METADATA에는 많은 하위 리소스가 있으므로 반환되는 값은 교착 상태가 발생한 하위 리소스에 따라 달라집니다.Because METADATA has many subresources, the value returned depends upon the subresource that has deadlocked. 예를 들어 METADATA.USER_TYPE는 user_type_id = <integer_value>를 반환합니다.For example, METADATA.USER_TYPE returns user_type_id = <integer_value>. METADATA 리소스 및 하위 리소스에 대한 자세한 내용은 sys.dm_tran_locks(Transact-SQL)를 참조하십시오.For more information about METADATA resources and subresources, see sys.dm_tran_locks (Transact-SQL).

HOBT.HOBT. 교착 상태와 관련된 힙 또는 B-트리를 나타냅니다.Represents a heap or b-tree involved in a deadlock.
이 추적 플래그에만 관련된 사항이 없습니다.None exclusive to this trace flag. 이 추적 플래그에만 관련된 사항이 없습니다.None exclusive to this trace flag.
추적 플래그 1204 예Trace Flag 1204 Example

다음 예에서는 추적 플래그 1204가 설정되어 있을 때의 출력을 보여 줍니다.The following example shows the output when trace flag 1204 is turned on. 이 경우 노드 1의 테이블은 인덱스가 없는 힙이고 노드 2의 테이블은 비클러스터형 인덱스가 있는 힙입니다.In this case, the table in Node 1 is a heap with no indexes, and the table in Node 2 is a heap with a nonclustered index. 노드 2의 인덱스 키는 교착 상태 발생 시 업데이트 중입니다.The index key in Node 2 is being updated when the deadlock occurs.

Deadlock encountered .... Printing deadlock information  
Wait-for graph  
  
Node:1  
  
RID: 6:1:20789:0               CleanCnt:3 Mode:X Flags: 0x2  
 Grant List 0:  
   Owner:0x0315D6A0 Mode: X          
     Flg:0x0 Ref:0 Life:02000000 SPID:55 ECID:0 XactLockInfo: 0x04D9E27C  
   SPID: 55 ECID: 0 Statement Type: UPDATE Line #: 6  
   Input Buf: Language Event:   
BEGIN TRANSACTION  
   EXEC usp_p2  
 Requested By:   
   ResType:LockOwner Stype:'OR'Xdes:0x03A3DAD0   
     Mode: U SPID:54 BatchID:0 ECID:0 TaskProxy:(0x04976374) Value:0x315d200 Cost:(0/868)  
  
Node:2  
  
KEY: 6:72057594057457664 (350007a4d329) CleanCnt:2 Mode:X Flags: 0x0  
 Grant List 0:  
   Owner:0x0315D140 Mode: X          
     Flg:0x0 Ref:0 Life:02000000 SPID:54 ECID:0 XactLockInfo: 0x03A3DAF4  
   SPID: 54 ECID: 0 Statement Type: UPDATE Line #: 6  
   Input Buf: Language Event:   
     BEGIN TRANSACTION  
       EXEC usp_p1  
 Requested By:   
   ResType:LockOwner Stype:'OR'Xdes:0x04D9E258   
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)  
  
Victim Resource Owner:  
 ResType:LockOwner Stype:'OR'Xdes:0x04D9E258   
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)  
추적 플래그 1222 예Trace Flag 1222 Example

다음 예에서는 추적 플래그 1222가 설정되어 있을 때의 출력을 보여 줍니다.The following example shows the output when trace flag 1222 is turned on. 이 경우 한 테이블은 인덱스가 없는 힙이고 다른 테이블은 비클러스터형 인덱스가 있는 힙입니다.In this case, one table is a heap with no indexes, and the other table is a heap with a nonclustered index. 두 번째 테이블의 인덱스 키는 교착 상태 발생 시 업데이트 중입니다.In the second table, the index key is being updated when the deadlock occurs.

deadlock-list  
 deadlock victim=process689978  
  process-list  
   process id=process6891f8 taskpriority=0 logused=868   
   waitresource=RID: 6:1:20789:0 waittime=1359 ownerId=310444   
   transactionname=user_transaction   
   lasttranstarted=2005-09-05T11:22:42.733 XDES=0x3a3dad0   
   lockMode=U schedulerid=1 kpid=1952 status=suspended spid=54   
   sbid=0 ecid=0 priority=0 transcount=2   
   lastbatchstarted=2005-09-05T11:22:42.733   
   lastbatchcompleted=2005-09-05T11:22:42.733   
   clientapp=Microsoft SQL Server Management Studio - Query   
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user   
   isolationlevel=read committed (2) xactid=310444 currentdb=6   
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200  
    executionStack  
     frame procname=AdventureWorks2016.dbo.usp_p1 line=6 stmtstart=202   
     sqlhandle=0x0300060013e6446b027cbb00c69600000100000000000000  
     UPDATE T2 SET COL1 = 3 WHERE COL1 = 1;       
     frame procname=adhoc line=3 stmtstart=44   
     sqlhandle=0x01000600856aa70f503b8104000000000000000000000000  
     EXEC usp_p1       
    inputbuf  
      BEGIN TRANSACTION  
       EXEC usp_p1  
   process id=process689978 taskpriority=0 logused=380   
   waitresource=KEY: 6:72057594057457664 (350007a4d329)     
   waittime=5015 ownerId=310462 transactionname=user_transaction   
   lasttranstarted=2005-09-05T11:22:44.077 XDES=0x4d9e258 lockMode=U   
   schedulerid=1 kpid=3024 status=suspended spid=55 sbid=0 ecid=0   
   priority=0 transcount=2 lastbatchstarted=2005-09-05T11:22:44.077   
   lastbatchcompleted=2005-09-05T11:22:44.077   
   clientapp=Microsoft SQL Server Management Studio - Query   
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user   
   isolationlevel=read committed (2) xactid=310462 currentdb=6   
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200  
    executionStack  
     frame procname=AdventureWorks2016.dbo.usp_p2 line=6 stmtstart=200   
     sqlhandle=0x030006004c0a396c027cbb00c69600000100000000000000  
     UPDATE T1 SET COL1 = 4 WHERE COL1 = 1;       
     frame procname=adhoc line=3 stmtstart=44   
     sqlhandle=0x01000600d688e709b85f8904000000000000000000000000  
     EXEC usp_p2       
    inputbuf  
      BEGIN TRANSACTION  
        EXEC usp_p2      
  resource-list  
   ridlock fileid=1 pageid=20789 dbid=6 objectname=AdventureWorks2016.dbo.T2   
   id=lock3136940 mode=X associatedObjectId=72057594057392128  
    owner-list  
     owner id=process689978 mode=X  
    waiter-list  
     waiter id=process6891f8 mode=U requestType=wait  
   keylock hobtid=72057594057457664 dbid=6 objectname=AdventureWorks2016.dbo.T1   
   indexname=nci_T1_COL1 id=lock3136fc0 mode=X   
   associatedObjectId=72057594057457664  
    owner-list  
     owner id=process6891f8 mode=X  
    waiter-list  
     waiter id=process689978 mode=U requestType=wait  

프로파일러 교착 상태 그래프 이벤트Profiler Deadlock Graph Event

교착 상태와 관련된 태스크 및 리소스를 그림으로 설명하는 SQL Profiler의 이벤트입니다.This is an event in SQL Profiler that presents a graphical depiction of the tasks and resources involved in a deadlock. 다음 예에서는 교착 상태 그래프 이벤트가 설정되어 있을 때 SQL Profiler의 출력을 보여 줍니다.The following example shows the output from SQL Profiler when the deadlock graph event is turned on.

ProfilerDeadlockGraphc

교착 상태 이벤트에 대한 자세한 내용은 Lock:Deadlock 이벤트 클래스를 참조하세요.For more information about the deadlock event, see Lock:Deadlock Event Class.

SQL 프로필러 교착 상태 그래프를 실행하는 방법에 대한 자세한 내용은 교착 상태 그래프 저장(SQL Server 프로파일러)을 참조하세요.For more information about running the SQL Profiler deadlock graph, see Save Deadlock Graphs (SQL Server Profiler).

교착 상태 처리Handling Deadlocks

SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스에서 교착 상태의 트랜잭션 중 처리하지 않을 트랜잭션이 선택되면 현재 배치가 종료되고 해당 트랜잭션이 롤백된 후 애플리케이션에 오류 메시지 1205가 반환됩니다.When an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine chooses a transaction as a deadlock victim, it terminates the current batch, rolls back the transaction, and returns error message 1205 to the application.

Your transaction (process ID #52) was deadlocked on {lock | communication buffer | thread} resources with another process and has been chosen as the deadlock victim. Rerun your transaction.

Transact-SQLTransact-SQL 쿼리를 전달하는 모든 애플리케이션은 교착 상태에서 처리되지 않을 수 있으므로 애플리케이션에 오류 메시지 1205를 트래핑할 수 있는 오류 처리기가 있어야 합니다.Because any application submitting Transact-SQLTransact-SQL queries can be chosen as the deadlock victim, applications should have an error handler that can trap error message 1205. 애플리케이션에서 오류를 트래핑하지 않으면 해당 트랜잭션이 롤백된 것을 모르고 계속 진행하여 오류가 발생할 수 있습니다.If an application does not trap the error, the application can proceed unaware that its transaction has been rolled back and errors can occur.

오류 메시지 1205를 트래핑하는 오류 처리기를 구현하면 애플리케이션에서 교착 상황을 처리하고 자동으로 교착 상태와 관련된 쿼리를 다시 전송하는 등의 동작을 취할 수 있습니다.Implementing an error handler that traps error message 1205 allows an application to handle the deadlock situation and take remedial action (for example, automatically resubmitting the query that was involved in the deadlock). 쿼리를 자동으로 다시 전송하므로 사용자는 교착 상태가 발생한 것을 알 필요가 없습니다.By resubmitting the query automatically, the user does not need to know that a deadlock occurred.

쿼리를 다시 전송하기 전에 애플리케이션이 일시 중지되어야 합니다.The application should pause briefly before resubmitting its query. 이때 교착 상태와 관련된 다른 트랜잭션이 완료되어 교착 상태의 원인이 되는 해당 잠금을 해제할 수 있습니다.This gives the other transaction involved in the deadlock a chance to complete and release its locks that formed part of the deadlock cycle. 이를 통해 다시 전송하는 쿼리에서 잠금을 요청할 때 교착 상태가 다시 발생할 가능성을 최소화할 수 있습니다.This minimizes the likelihood of the deadlock reoccurring when the resubmitted query requests its locks.

교착 상태 최소화Minimizing Deadlocks

교착 상태를 완전히 피할 수는 없지만 특정 코딩 규칙을 따르면 교착 상태가 발생하는 기회를 최소화할 수 있습니다.Although deadlocks cannot be completely avoided, following certain coding conventions can minimize the chance of generating a deadlock. 교착 상태를 최소화하면 트랜잭션 처리량이 늘어나고 더 적은 수의 트랜잭션이 다음과 같이 되므로 시스템 오버헤드가 줄어듭니다.Minimizing deadlocks can increase transaction throughput and reduce system overhead because fewer transactions are:

  • 롤백되어 트랜잭션에 의해 수행된 모든 작업이 실행 취소됩니다.Rolled back, undoing all the work performed by the transaction.
  • 교착 상태 발생 시 롤백되었으므로 애플리케이션에 의해 다시 전송됩니다.Resubmitted by applications because they were rolled back when deadlocked.

교착 상태를 최소화하려면To help minimize deadlocks:

  • 같은 순서로 개체에 액세스합니다.Access objects in the same order.
  • 트랜잭션에서 사용자 상호 작용을 피합니다.Avoid user interaction in transactions.
  • 트랜잭션을 하나의 일괄 처리로 짧게 유지합니다.Keep transactions short and in one batch.
  • 낮은 격리 수준을 사용합니다.Use a lower isolation level.
  • 행 버전 관리 기반의 격리 수준을 사용합니다.Use a row versioning-based isolation level.
    • READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 ON으로 설정하여 커밋된 읽기 트랜잭션이 행 버전 관리를 사용할 수 있도록 합니다.Set READ_COMMITTED_SNAPSHOT database option ON to enable read-committed transactions to use row versioning.
    • 스냅샷 격리를 사용합니다.Use snapshot isolation.
  • 바인딩된 연결을 사용합니다.Use bound connections.

같은 순서로 개체에 액세스합니다.Access Objects in the same order

모든 동시 트랜잭션이 같은 순서로 개체에 액세스하면 교착 상태의 발생 가능성이 줄어듭니다.If all concurrent transactions access objects in the same order, deadlocks are less likely to occur. 예를 들어 두 개의 동시 트랜잭션이 Supplier 테이블에 대해 잠금을 얻은 다음, Part 테이블에 대해 잠금을 얻으면 다른 트랜잭션이 완료될 때까지 한 트랜잭션이 Supplier 테이블에서 차단됩니다.For example, if two concurrent transactions obtain a lock on the Supplier table and then on the Part table, one transaction is blocked on the Supplier table until the other transaction is completed. 첫 번째 트랜잭션이 커밋되거나 롤백된 후 두 번째가 계속되므로 교착 상태는 발생하지 않습니다.After the first transaction commits or rolls back, the second continues, and a deadlock does not occur. 모든 데이터 수정에 대해 저장 프로시저를 사용하면 개체 액세스 순서를 표준화할 수 있습니다.Using stored procedures for all data modifications can standardize the order of accessing objects.

deadlock2

트랜잭션에서 사용자 상호 작용을 피합니다.Avoid user interaction in Transactions

사용자 개입 없이 실행되는 일괄 처리의 속도는 애플리케이션의 매개 변수 요청 프롬프트에 대한 응답 등 사용자가 수동으로 쿼리에 응답해야 하는 경우의 속도에 비해 매우 빠르므로 사용자 상호 작용을 포함하는 트랜잭션은 작성하지 않는 것이 좋습니다.Avoid writing transactions that include user interaction, because the speed of batches running without user intervention is much faster than the speed at which a user must manually respond to queries, such as replying to a prompt for a parameter requested by an application. 예를 들어 트랜잭션이 사용자 입력을 기다리고 있는데 사용자가 식사를 하러 가거나 퇴근한 경우 사용자는 트랜잭션을 완료할 수 없습니다.For example, if a transaction is waiting for user input and the user goes to lunch or even home for the weekend, the user delays the transaction from completing. 이 경우 트랜잭션에서 보유한 잠금은 트랜잭션이 커밋 또는 롤백되어야 해제되므로 시스템 처리량이 줄어듭니다.This degrades system throughput because any locks held by the transaction are released only when the transaction is committed or rolled back. 교착 상태가 발생하지 않아도 같은 리소스에 액세스하는 다른 트랜잭션은 해당 트랜잭션이 완료될 때까지 차단됩니다.Even if a deadlock situation does not arise, other transactions accessing the same resources are blocked while waiting for the transaction to complete.

트랜잭션을 하나의 일괄 처리로 짧게 유지Keep Transactions short and in one batch

교착 상태는 보통 오래 실행되는 여러 개의 트랜잭션이 같은 데이터베이스에서 동시에 실행될 때 발생합니다.A deadlock typically occurs when several long-running transactions execute concurrently in the same database. 트랜잭션 실행 시간이 길수록 배타적 또는 업데이트 잠금 보유 시간이 길어지므로 다른 작업을 차단하고 교착 상태를 일으킬 수 있습니다.The longer the transaction, the longer the exclusive or update locks are held, blocking other activity and leading to possible deadlock situations.

트랜잭션을 하나의 일괄 처리로 유지하면 트랜잭션 중 네트워크 왕복이 최소화되므로 트랜잭션을 완료하고 잠금을 해제하는 데 걸리는 지연 시간을 줄일 수 있습니다.Keeping transactions in one batch minimizes network roundtrips during a transaction, reducing possible delays in completing the transaction and releasing locks.

낮은 격리 수준을 사용합니다.Use a lower Isolation Level

트랜잭션을 더 낮은 격리 수준에서 실행할 수 있는지 확인합니다.Determine whether a transaction can run at a lower isolation level. 커밋된 읽기를 구현하면 트랜잭션에서는 처음 트랜잭션이 완료될 때까지 기다리지 않고 다른 트랜잭션에서 이전에 읽은 수정되지 않은 데이터를 읽을 수 있습니다.Implementing read committed allows a transaction to read data previously read (not modified) by another transaction without waiting for the first transaction to complete. 커밋된 읽기 등 낮은 격리 수준을 사용하면 순차 가능 등의 높은 격리 수준보다 짧은 기간 동안 공유 잠금을 보유합니다.Using a lower isolation level, such as read committed, holds shared locks for a shorter duration than a higher isolation level, such as serializable. 그 결과 잠금 경합이 줄어듭니다.This reduces locking contention.

행 버전 관리 기반의 격리 수준 사용Use a Row Versioning-based Isolation Level

READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 ON으로 설정하면 커밋된 읽기 격리 수준에서 실행되는 트랜잭션은 읽기 작업 동안 공유 잠금 대신 행 버전 관리를 사용합니다.When the READ_COMMITTED_SNAPSHOT database option is set ON, a transaction running under read committed isolation level uses row versioning rather than shared locks during read operations.

참고

일부 애플리케이션은 커밋된 읽기 격리의 잠금과 차단에 의존합니다.Some applications rely upon locking and blocking behavior of read committed isolation. 이러한 애플리케이션의 경우 이 옵션을 설정하기 전에 몇 가지 사항을 변경해야 합니다.For these applications, some change is required before this option can be enabled.

스냅샷 격리에서도 읽기 작업 중 공유 잠금을 사용하지 않는 행 버전 관리를 사용합니다.Snapshot isolation also uses row versioning, which does not use shared locks during read operations. 스냅샷 격리 상태에서 트랜잭션을 실행하려면 먼저 ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정해야 합니다.Before a transaction can run under snapshot isolation, the ALLOW_SNAPSHOT_ISOLATION database option must be set ON.

읽기 작업과 쓰기 작업 간에 발생할 수 있는 교착 상태를 최소화하려면 이러한 격리 수준을 구현합니다.Implement these isolation levels to minimize deadlocks that can occur between read and write operations.

바인딩된 연결을 사용합니다.Use bound connections

바인딩된 연결을 사용하면 같은 애플리케이션에서 열어 놓은 둘 이상의 연결을 함께 사용할 수 있습니다.Using bound connections, two or more connections opened by the same application can cooperate with each other. 보조 연결에서 얻은 잠금은 기본 연결에서 얻은 것과 같이 유지되며 반대의 경우도 마찬가지입니다.Any locks acquired by the secondary connections are held as if they were acquired by the primary connection, and vice versa. 따라서 서로를 차단하지 않습니다.Therefore they do not block each other.

잠금 분할Lock Partitioning

잠금을 확보하고 해제하는 과정에서는 내부 잠금 리소스에 대한 경합이 발생하기 때문에 대규모 컴퓨터 시스템의 경우 자주 참조되는 개체를 잠그면 성능이 저하될 수 있습니다.For large computer systems, locks on frequently referenced objects can become a performance bottleneck as acquiring and releasing locks place contention on internal locking resources. 잠금 분할은 하나의 잠금 리소스를 여러 잠금 리소스로 분할하여 잠금 성능을 높입니다.Lock partitioning enhances locking performance by splitting a single lock resource into multiple lock resources. 이 기능은 CPU가 16개 이상인 시스템에서만 사용할 수 있고 자동으로 설정되며 해제할 수는 없습니다.This feature is only available for systems with 16 or more CPUs, and is automatically enabled and cannot be disabled. 개체 잠금만 분할할 수 있습니다. 하위 유형이 있는 개체 잠금은 분할할 수 없습니다.Only object locks can be partitioned.Object locks that have a subtype are not partitioned. 자세한 내용은 sys.dm_tran_locks(Transact-SQL)를 참조하세요.For more information, see sys.dm_tran_locks (Transact-SQL).

잠금 분할 이해Understanding Lock Partitioning

잠금 태스크에서는 몇 가지 공유 리소스에 액세스하게 되며 잠금 분할을 통해 이 중 두 가지 리소스에 대한 액세스를 최적화할 수 있습니다.Locking tasks access several shared resources, two of which are optimized by lock partitioning:

  • Spinlock.Spinlock. 행 또는 테이블과 같은 잠금 리소스에 대한 액세스를 제어합니다.This controls access to a lock resource, such as a row or a table.

    잠금 분할을 사용하지 않으면 하나의 spinlock이 단일 잠금 리소스에 대한 모든 잠금 요청을 관리하게 됩니다.Without lock partitioning, one spinlock manages all lock requests for a single lock resource. 작업량이 많은 시스템에서는 여러 잠금 요청이 spinlock을 사용하기 위해 대기하므로 경합이 발생할 수 있습니다.On systems that experience a large volume of activity, contention can occur as lock requests wait for the spinlock to become available. 이러한 상황에서 잠금을 획득하게 되면 병목이 발생하여 성능을 저하시킬 수 있습니다.Under this situation, acquiring locks can become a bottleneck and can negatively impact performance.

    잠금 분할은 단일 잠금 리소스를 여러 잠금 리소스로 분할하여 여러 spinlock에 로드를 분산함으로써 단일 잠금 리소스에 대한 경합을 줄입니다.To reduce contention on a single lock resource, lock partitioning splits a single lock resource into multiple lock resources to distribute the load across multiple spinlocks.

  • 메모리.Memory. 잠금 리소스 구조를 저장하는 데 사용됩니다.This is used to store the lock resource structures.

    spinlock이 확보되면 잠금 구조가 메모리에 저장된 다음 액세스되고 경우에 따라 수정됩니다.Once the spinlock is acquired, lock structures are stored in memory and then accessed and possibly modified. 잠금 액세스를 여러 리소스로 분산하면 CPU 간에 메모리 블록을 전송할 필요가 없으므로 성능이 향상됩니다.Distributing lock access across multiple resources helps to eliminate the need to transfer memory blocks between CPUs, which will help to improve performance.

잠금 분할 구현 및 모니터링Implementing and Monitoring Lock Partitioning

CPU가 16개 이상인 시스템의 경우 잠금 분할이 기본적으로 설정됩니다.Lock partitioning is turned on by default for systems with 16 or more CPUs. 잠금 분할을 사용하면 SQL ServerSQL Server 오류 로그에 정보 메시지가 기록됩니다.When lock partitioning is enabled, an informational message is recorded in the SQL ServerSQL Server error log.

분할된 리소스에 대해 잠금을 확보하는 경우When acquiring locks on a partitioned resource:

  • NL, SCH-S, IS, IU 및 IX 잠금 모드만 단일 파티션에 대해 확보됩니다.Only NL, SCH-S, IS, IU, and IX lock modes are acquired on a single partition.

  • NL, SCH-S, IS, IU 및 IX 이외의 모드에서 공유 잠금(S), 배타적 잠금(X) 등의 잠금은 파티션 ID가 0으로 시작하고 파티션 ID 순서를 따르는 모든 파티션에 대해 확보되어야 합니다.Shared (S), exclusive (X), and other locks in modes other than NL, SCH-S, IS, IU, and IX must be acquired on all partitions starting with partition ID 0 and following in partition ID order. 각 파티션은 효율적인 별도의 잠금이 되므로 분할된 리소스에 이러한 대한 잠금은 동일한 모드에서 분할되지 않은 리소스에 대한 잠금보다 메모리를 더 많이 사용합니다.These locks on a partitioned resource will use more memory than locks in the same mode on a non-partitioned resource since each partition is effectively a separate lock. 메모리 증가는 파티션의 수에 따라 결정됩니다.The memory increase is determined by the number of partitions. Windows 성능 모니터에서 SQL ServerSQL Server 잠금 카운터에는 분할된 잠금과 분할되지 않은 잠금에 사용되는 메모리에 대한 정보가 표시됩니다.The SQL ServerSQL Server lock counters in the Windows Performance Monitor will display information about memory used by partitioned and non-partitioned locks.

트랜잭션이 시작되면 파티션에 트랜잭션이 할당됩니다.A transaction is assigned to a partition when the transaction starts. 트랜잭션의 경우 분할할 수 있는 모든 잠금 요청에는 트랜잭션에 할당된 파티션이 사용됩니다.For the transaction, all lock requests that can be partitioned use the partition assigned to that transaction. 이러한 방법으로 동일한 개체의 잠금 리소스에 대한 여러 트랜잭션의 액세스가 여러 파티션으로 분산됩니다.By this method, access to lock resources of the same object by different transactions is distributed across different partitions.

sys.dm_tran_locks 동적 관리 뷰의 resource_lock_partition 열은 잠금 분할 리소스에 대한 잠금 파티션 ID를 제공합니다.The resource_lock_partition column in the sys.dm_tran_locks Dynamic Management View provides the lock partition ID for a lock partitioned resource. 자세한 내용은 sys.dm_tran_locks(Transact-SQL)를 참조하세요.For more information, see sys.dm_tran_locks (Transact-SQL).

잠금 분할 작업Working with Lock Partitioning

다음은 잠금 분할을 보여 주는 코드 예제입니다.The following code examples illustrate lock partitioning. 이 예제에서는 서로 다른 두 세션에서 실행되는 두 가지 트랜잭션을 통해 CPU가 16개인 시스템의 잠금 분할 동작을 보여 줍니다.In the examples, two transactions are executed in two different sessions in order to show lock partitioning behavior on a computer system with 16 CPUs.

다음 Transact-SQLTransact-SQL 문은 이후에 나오는 예제에서 사용되는 테스트 개체를 만듭니다.These Transact-SQLTransact-SQL statements create test objects that are used in the examples that follow.

-- Create a test table.  
CREATE TABLE TestTable  (col1 int);  
GO  
  
-- Create a clustered index on the table.  
CREATE CLUSTERED INDEX ci_TestTable   
    ON TestTable (col1);  
GO  
  
-- Populate the table.  
INSERT INTO TestTable VALUES (1);  
GO  

예 1Example A

세션 1:Session 1:

트랜잭션에서 SELECT 문이 실행됩니다.A SELECT statement is executed under a transaction. HOLDLOCK 잠금 힌트로 인해 이 문은 해당 테이블에 대해 IS(내재된 공유) 잠금을 획득하여 유지합니다. 이 그림에서는 행 잠금 및 페이지 잠금이 무시됩니다.Because of the HOLDLOCK lock hint, this statement will acquire and retain an Intent shared (IS) lock on the table (for this illustration, row and page locks are ignored). IS 잠금은 트랜잭션에 할당된 파티션에 대해서만 획득할 수 있습니다.The IS lock will be acquired only on the partition assigned to the transaction. 이 예에서는 파티션 ID 7에 대해 IS 잠금을 획득했다고 가정합니다.For this example, it is assumed that the IS lock is acquired on partition ID 7.

-- Start a transaction.  
BEGIN TRANSACTION  
    -- This SELECT statement will acquire an IS lock on the table.  
    SELECT col1  
    FROM TestTable  
    WITH (HOLDLOCK);  

세션 2:Session 2:

트랜잭션이 시작되고 이 트랜잭션에서 실행되는 SELECT 문이 테이블에 대한 S(공유) 잠금을 획득 및 유지합니다.A transaction is started, and the SELECT statement running under this transaction will acquire and retain a shared (S) lock on the table. S 잠금은 모든 파티션에 대해 확보되므로 각 파티션에 대해 하나씩 잠금이 생성되어 여러 테이블이 잠기게 됩니다.The S lock will be acquired on all partitions which results in multiple table locks, one for each partition. 예를 들어 CPU가 16개인 시스템에서 잠금 파티션 ID 0-15까지 16개의 잠금이 생성됩니다.For example, on a 16-cpu system, 16 S locks will be issued across lock partition IDs 0-15. S 잠금은 세션 1의 트랜잭션에 의해 파티션 ID 7에 확보된 IS 잠금과 호환되므로 트랜잭션 간에 차단이 발생하지 않습니다.Because the S lock is compatible with the IS lock being held on partition ID 7 by the transaction in session 1, there is no blocking between transactions.

BEGIN TRANSACTION  
    SELECT col1  
    FROM TestTable  
    WITH (TABLOCK, HOLDLOCK);  

세션 1:Session 1:

세션 1에서 아직 활성화되어 있는 트랜잭션에서 다음 SELECT 문이 실행됩니다.The following SELECT statement is executed under the transaction that is still active under session 1. X(배타적) 테이블 잠금 힌트로 인해 트랜잭션이 테이블에 대해 X 잠금을 획득하려 합니다.Because of the exclusive (X) table lock hint, the transaction will attempt to acquire an X lock on the table. 그러나 세션 2의 트랜잭션에 의해 확보된 S 잠금이 파티션 ID 0에서 X 잠금을 차단합니다.However, the S lock that is being held by the transaction in session 2 will block the X lock at partition ID 0.

SELECT col1  
FROM TestTable  
WITH (TABLOCKX);  

예 2Example B

세션 1:Session 1:

트랜잭션에서 SELECT 문이 실행됩니다.A SELECT statement is executed under a transaction. HOLDLOCK 잠금 힌트로 인해 이 문은 해당 테이블에 대해 IS(내재된 공유) 잠금을 획득하여 유지합니다. 이 그림에서는 행 잠금 및 페이지 잠금이 무시됩니다.Because of the HOLDLOCK lock hint, this statement will acquire and retain an Intent shared (IS) lock on the table (for this illustration, row and page locks are ignored). IS 잠금은 트랜잭션에 할당된 파티션에 대해서만 획득할 수 있습니다.The IS lock will be acquired only on the partition assigned to the transaction. 이 예에서는 파티션 ID 6에 대해 IS 잠금을 획득했다고 가정합니다.For this example, it is assumed that the IS lock is acquired on partition ID 6.

-- Start a transaction.  
BEGIN TRANSACTION  
    -- This SELECT statement will acquire an IS lock on the table.  
    SELECT col1  
    FROM TestTable  
    WITH (HOLDLOCK);  

세션 2:Session 2:

트랜잭션에서 SELECT 문이 실행됩니다.A SELECT statement is executed under a transaction. TABLOCKX 잠금 힌트로 인해 트랜잭션이 테이블에 대해 X(배타적) 잠금을 획득하려 합니다.Because of the TABLOCKX lock hint, the transaction tries to acquire an exclusive (X) lock on the table. 파티션 ID가 0으로 시작하는 모든 파티션에 대해 획득되어야 하므로Remember that the X lock must be acquired on all partitions starting with partition ID 0. X 잠금은 0-5의 모든 파티션 ID에 대해 획득되지만 파티션 ID 6에 획득된 IS 잠금에 의해 차단됩니다.The X lock will be acquired on all partitions IDs 0-5 but will be blocked by the IS lock that is acquired on partition ID 6.

아직 X 잠금이 획득되지 않은 파티션 ID 7-15에서 다른 트랜잭션이 계속 잠금을 획득할 수 있습니다.On partition IDs 7-15 that the X lock has not yet reached, other transactions can continue to acquire locks.

BEGIN TRANSACTION  
    SELECT col1  
    FROM TestTable  
    WITH (TABLOCKX, HOLDLOCK);  

SQL Server 데이터베이스 엔진SQL Server Database Engine에서 행 버전 관리 기반 격리 수준 사용.Row Versioning-based Isolation Levels in the SQL Server 데이터베이스 엔진SQL Server Database Engine

SQL Server 2005(9.x)SQL Server 2005 (9.x)부터 SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 기존 격리 수준을 구현한 커밋된 읽기를 제공하여 행 버전 관리를 사용하는 문 수준 스냅샷을 제공합니다.Starting with SQL Server 2005(9.x)SQL Server 2005 (9.x), the SQL Server 데이터베이스 엔진SQL Server Database Engine offers an implementation of an existing transaction isolation level, read committed, that provides a statement level snapshot using row versioning. 또한 SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 트랜잭션 격리 수준인 스냅샷이 도입되어 행 버전 관리를 사용하는 트랜잭션 수준 스냅샷을 제공합니다.SQL Server 데이터베이스 엔진SQL Server Database Engine also offers a transaction isolation level, snapshot, that provides a transaction level snapshot also using row versioning.

SQL ServerSQL Server에서 행 버전 관리는 행을 수정하거나 삭제할 때 쓰기 시 복사 메커니즘을 호출하는 일반적인 방법입니다.Row versioning is a general framework in SQL ServerSQL Server that invokes a copy-on-write mechanism when a row is modified or deleted. 이렇게 하려면 트랜잭션을 실행하는 동안 트랜잭션의 일관성 있는 이전 상태가 요구되는 트랜잭션에서 이전 기존 행 버전을 사용할 수 있어야 합니다.This requires that while the transaction is running, the old version of the row must be available for transactions that require an earlier transactionally consistent state. 행 버전 관리는 다음 용도로 사용됩니다.Row versioning is used to do the following:

  • 트리거에 inserteddeleted 테이블 작성.Build the inserted and deleted tables in triggers. 트리거에 의해 수정된 모든 행의 버전이 지정됩니다.Any rows modified by the trigger are versioned. 여기에는 트리거를 실행한 문에 의해 수정된 행과 트리거에 의해 수정된 모든 데이터가 포함됩니다.This includes the rows modified by the statement that launched the trigger, as well as any data modifications made by the trigger.
  • MARS(Multiple Active Result Sets) 지원.Support Multiple Active Result Sets (MARS). 활성 결과 집합이 있을 때 MARS 세션에서 INSERT, UPDATE 또는 DELETE와 같은 데이터 수정 문을 실행하면 이 수정 문의 영향을 받는 행의 버전이 지정됩니다.If a MARS session issues a data modification statement (such as INSERT, UPDATE, or DELETE) at a time there is an active result set, the rows affected by the modification statement are versioned.
  • ONLINE 옵션을 지정하는 인덱스 작업 지원Support index operations that specify the ONLINE option.
  • 행 버전 관리 기반 트랜잭션 격리 수준 지원Support row versioning-based transaction isolation levels:
    • 행 버전 관리를 사용하여 문 수준의 읽기 일관성을 유지하는 새로운 커밋된 읽기 격리 수준 구현A new implementation of read committed isolation level that uses row versioning to provide statement-level read consistency.
    • 트랜잭션 수준의 읽기 일관성을 유지하는 새로운 스냅샷 격리 수준A new isolation level, snapshot, to provide transaction-level read consistency.

tempdb 데이터베이스에는 버전 저장소로 사용할 공간이 충분해야 합니다.The tempdb database must have enough space for the version store. tempdb이 꽉 차면 업데이트 작업이 버전 생성을 중단하고 계속 진행되지만 필요한 특정 행 버전이 더 이상 존재하지 않으므로 읽기 작업이 실패할 수 있습니다.When tempdb is full, update operations will stop generating versions and continue to succeed, but read operations might fail because a particular row version that is needed no longer exists. 이것은 트리거, MARS 및 온라인 인덱싱 등의 작업에 영향을 줍니다.This affects operations like triggers, MARS, and online indexing.

커밋된 읽기 및 스냅샷 트랜잭션에 행 버전 관리를 사용하는 과정은 다음 두 단계로 이루어집니다.Using row versioning for read-committed and snapshot transactions is a two-step process:

  1. READ_COMMITTED_SNAPSHOTALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션 중 하나 또는 모두를 ON에 설정합니다.Set either or both the READ_COMMITTED_SNAPSHOT and ALLOW_SNAPSHOT_ISOLATION database options ON.

  2. 애플리케이션에서 적절한 트랜잭션 격리 수준을 설정합니다.Set the appropriate transaction isolation level in an application:

    • READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 ON으로 설정하면 커밋된 읽기 격리 수준을 설정하는 트랜잭션에 행 버전 관리가 사용됩니다.When the READ_COMMITTED_SNAPSHOT database option is ON, transactions setting the read committed isolation level use row versioning.
    • ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정하면 트랜잭션에서 스냅샷 격리 수준을 설정할 수 있습니다.When the ALLOW_SNAPSHOT_ISOLATION database option is ON, transactions can set the snapshot isolation level.

READ_COMMITTED_SNAPSHOT 또는 ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정하면 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 행 버전 관리를 사용하여 데이터를 조작하는 각 트랜잭션에 XSN(트랜잭션 시퀀스 번호)을 할당합니다.When either READ_COMMITTED_SNAPSHOT or ALLOW_SNAPSHOT_ISOLATION database option is set ON, the SQL Server 데이터베이스 엔진SQL Server Database Engine assigns a transaction sequence number (XSN) to each transaction that manipulates data using row versioning. 트랜잭션은 BEGIN TRANSACTION 문이 실행될 때 시작합니다.Transactions start at the time a BEGIN TRANSACTION statement is executed. 그러나 트랜잭션 시퀀스 번호는 BEGIN TRANSACTION 문 이후 첫 번째 읽기 또는 쓰기 작업이 실행될 때 시작합니다.However, the transaction sequence number starts with the first read or write operation after the BEGIN TRANSACTION statement. 트랜잭션 시퀀스 번호는 할당될 때마다 1씩 증가합니다.The transaction sequence number is incremented by one each time it is assigned.

READ_COMMITTED_SNAPSHOT 또는 ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정하면 데이터베이스에서 수행된 모든 데이터 수정 내용에 대한 논리적 복사본(버전)이 유지됩니다.When either the READ_COMMITTED_SNAPSHOT or ALLOW_SNAPSHOT_ISOLATION database options are ON, logical copies (versions) are maintained for all data modifications performed in the database. 특정 트랜잭션에 의해 행이 수정될 때마다 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스는 행의 이전에 커밋된 이미지 버전을 tempdb에 저장합니다.Every time a row is modified by a specific transaction, the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine stores a version of the previously committed image of the row in tempdb. 각 버전은 행을 변경한 트랜잭션의 트랜잭션 시퀀스 번호로 표시됩니다.Each version is marked with the transaction sequence number of the transaction that made the change. 수정된 행의 여러 버전은 연결 목록을 통해 체인으로 연결됩니다.The versions of modified rows are chained using a link list. 최신 행 값은 항상 현재 데이터베이스에 저장되고 tempdb에 저장된 버전 지정된 행과 체인으로 연결되어 있습니다.The newest row value is always stored in the current database and chained to the versioned rows stored in tempdb.

참고

LOB(Large Object) 수정 내용의 경우 변경된 조각만 tempdb의 버전 저장소에 복사됩니다.For modification of large objects (LOBs), only the changed fragment is copied to the version store in tempdb.

행 버전은 행 버전 관리 기반 격리 수준으로 실행되는 트랜잭션의 요구 사항을 만족할 때까지 유지됩니다.Row versions are held long enough to satisfy the requirements of transactions running under row versioning-based isolation levels. SQL Server 데이터베이스 엔진SQL Server Database Engine은 가장 오래된 유용한 트랜잭션 시퀀스 번호를 추적하여 해당 번호보다 낮은 트랜잭션 시퀀스 번호로 표시된 모든 행 버전을 주기적으로 삭제합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine tracks the earliest useful transaction sequence number and periodically deletes all row versions stamped with transaction sequence numbers that are lower than the earliest useful sequence number.

두 가지 데이터베이스 옵션을 모두 OFF로 설정하면 트리거 또는 MARS 세션에 의해 수정되었거나 ONLINE 인덱스 작업에서 읽은 행에만 버전이 지정됩니다.When both database options are set to OFF, only rows modified by triggers or MARS sessions, or read by ONLINE index operations, are versioned. 이러한 행 버전은 더 이상 필요하지 않을 경우 해제됩니다.Those row versions are released when no longer needed. 백그라운드 스레드가 주기적으로 실행되어 오래되어 필요 없는 행 버전을 제거합니다.A background thread periodically executes to remove stale row versions.

참고

짧게 실행되는 트랜잭션의 경우 수정된 행의 버전이 tempdb 데이터베이스의 디스크 파일에 작성되지 않고 버퍼 풀에 캐시될 수 있습니다.For short-running transactions, a version of a modified row may get cached in the buffer pool without getting written into the disk files of the tempdb database. 버전이 지정된 행이 일시적으로 필요한 경우에는 버퍼 풀에서 삭제되며 이것이 반드시 I/O 오버헤드를 유발하는 것은 아닐 수도 있습니다.If the need for the versioned row is short-lived, it will simply get dropped from the buffer pool and may not necessarily incur I/O overhead.

데이터를 읽는 경우의 동작Behavior when reading data

행 버전 관리 기반 격리 데이터 읽기 수준으로 트랜잭션이 실행되는 경우에는 읽기 작업에서 읽고 있는 데이터에 대한 공유(S) 잠금을 획득하지 못하므로 데이터를 수정하는 트랜잭션을 차단하지 못합니다.When transactions running under row versioning-based isolation read data, the read operations do not acquire shared (S) locks on the data being read, and therefore do not block transactions that are modifying data. 또한 획득한 잠금 수가 감소함에 따라 리소스 잠금으로 인한 오버헤드가 최소화됩니다.Also, the overhead of locking resources is minimized as the number of locks acquired is reduced. 행 버전 관리를 사용하는 커밋된 읽기 격리 및 스냅샷 격리는 버전이 지정된 데이터에 대해 문 수준 또는 트랜잭션 수준의 읽기 일관성을 유지하도록 디자인되었습니다.Read committed isolation using row versioning and snapshot isolation are designed to provide statement-level or transaction-level read consistencies of versioned data.

행 버전 관리 기반 격리 수준에서 실행되는 트랜잭션을 포함하여 모든 쿼리는 컴파일 및 실행 중에 Sch-S(스키마 안정성) 잠금을 획득합니다.All queries, including transactions running under row versioning-based isolation levels, acquire Sch-S (schema stability) locks during compilation and execution. 이 때문에 동시 트랜잭션이 테이블에 대해 Sch-M(스키마 수정) 잠금을 유지하면 쿼리가 차단됩니다.Because of this, queries are blocked when a concurrent transaction holds a Sch-M (schema modification) lock on the table. 예를 들어 DDL(데이터 정의 언어) 작업은 테이블의 스키마 정보를 수정하기 전에 Sch-M 잠금을 획득합니다.For example, a data definition language (DDL) operation acquires a Sch-M lock before it modifies the schema information of the table. 행 버전 관리 기반 격리 수준에서 실행되는 쿼리 트랜잭션을 포함하여 Sch-S 잠금을 획득하려고 시도하는 쿼리 트랜잭션은 차단됩니다.Query transactions, including those running under a row versioning-based isolation level, are blocked when attempting to acquire a Sch-S lock. 반대로 Sch-S 잠금을 유지하는 쿼리는 Sch-M 잠금을 획득하려고 시도하는 동시 트랜잭션을 차단합니다.Conversely, a query holding a Sch-S lock blocks a concurrent transaction that attempts to acquire a Sch-M lock.

스냅샷 격리 수준을 사용하는 트랜잭션이 시작되면 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스에서 현재 활성화된 모든 트랜잭션을 기록합니다.When a transaction using the snapshot isolation level starts, the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine records all of the currently active transactions. 스냅샷 트랜잭션에서 버전 체인이 있는 행을 읽으면 SQL Server 데이터베이스 엔진SQL Server Database Engine이 체인을 추적하여 다음과 같은 트랜잭션 시퀀스 번호가 있는 행을 검색합니다.When the snapshot transaction reads a row that has a version chain, the SQL Server 데이터베이스 엔진SQL Server Database Engine follows the chain and retrieves the row where the transaction sequence number is:

  • 행을 읽는 스냅샷 트랜잭션의 시퀀스 번호보다 낮으면서 가장 근사한 번호Closest to but lower than the sequence number of the snapshot transaction reading the row.

  • 스냅샷 트랜잭션이 시작되었을 때 활성화된 트랜잭션의 목록에 없는 번호Not in the list of the transactions active when the snapshot transaction started.

스냅샷 트랜잭션에 따라 수행된 읽기 작업에서는 스냅샷 트랜잭션이 시작되었을 때 커밋된 각 행의 마지막 버전을 검색합니다.Read operations performed by a snapshot transaction retrieve the last version of each row that had been committed at the time the snapshot transaction started. 따라서 트랜잭션의 시작 부분에 데이터가 위치하게 되므로 데이터의 스냅샷 트랜잭션이 일관되게 유지됩니다.This provides a transactionally consistent snapshot of the data as it existed at the start of the transaction.

행 버전 관리가 사용된 커밋된 읽기 트랜잭션도 이와 비슷한 방식으로 작동합니다.Read-committed transactions using row versioning operate in much the same way. 다만 커밋된 읽기 트랜잭션에서는 행 버전을 선택할 때 고유한 트랜잭션 시퀀스 번호가 사용되지 않는다는 점이 다릅니다.The difference is that the read-committed transaction does not use its own transaction sequence number when choosing row versions. 문이 시작될 때마다 커밋된 읽기 트랜잭션에서는 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스에 대해 생성된 가장 최근의 트랜잭션 시퀀스 번호를 읽습니다.Each time a statement is started, the read-committed transaction reads the latest transaction sequence number issued for that instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine. 이 트랜잭션 시퀀스 번호는 해당 문에 대해 올바른 행 버전을 선택하는 데 사용됩니다.This is the transaction sequence number used to select the correct row versions for that statement. 이러한 방법으로 커밋된 읽기 트랜잭션에서 각 문의 시작 부분에 있는 데이터의 스냅샷을 확인할 수 있습니다.This allows read-committed transactions to see a snapshot of the data as it exists at the start of each statement.

참고

행 버전 관리를 사용하는 커밋된 읽기 트랜잭션은 문 수준에서 트랜잭션이 일관된 데이터 뷰를 제공하지만 이 유형의 트랜잭션에서 생성하거나 액세스한 행 버전은 해당 트랜잭션이 완료될 때까지 유지됩니다.Even though read-committed transactions using row versioning provides a transactionally consistent view of the data at a statement level, row versions generated or accessed by this type of transaction are maintained until the transaction completes.

데이터를 수정하는 경우의 동작Behavior when modifying data

행 버전 관리가 사용되는 커밋된 읽기 트랜잭션에서는 데이터 값을 읽을 때 데이터 행에 업데이트(U) 잠금이 적용되는 차단 검색을 사용하여 업데이트할 행을 선택합니다.In a read-committed transaction using row versioning, the selection of rows to update is done using a blocking scan where an update (U) lock is taken on the data row as data values are read. 이것은 행 버전 관리를 사용하지 않는 커밋된 읽기 트랜잭션과 동일합니다.This is the same as a read-committed transaction that does not use row versioning. 데이터 행이 업데이트 조건에 맞지 않으면 해당 행의 업데이트 잠금이 해제되고 그 다음 행이 잠겨 검색됩니다.If the data row does not meet the update criteria, the update lock is released on that row and the next row is locked and scanned.

스냅샷 격리 수준으로 실행되는 트랜잭션은 제약 조건을 적용하기 위해 수정 내용을 수행하기 전에 데이터에 대한 잠금을 획득하는 낙관적 데이터 수정 방법을 사용합니다.Transactions running under snapshot isolation take an optimistic approach to data modification by acquiring locks on data before performing the modification only to enforce constraints. 그렇지 않으면 데이터가 수정될 때까지 데이터에 대한 잠금도 획득되지 않습니다.Otherwise, locks are not acquired on data until the data is to be modified. 스냅샷 트랜잭션은 데이터 행이 업데이트 조건에 맞으면 이 스냅샷 트랜잭션이 시작된 후 커밋된 동시 트랜잭션에 의해 해당 데이터 행이 수정되지 않았는지 확인합니다.When a data row meets the update criteria, the snapshot transaction verifies that the data row has not been modified by a concurrent transaction that committed after the snapshot transaction began. 스냅샷 트랜잭션이 아닌 다른 트랜잭션에 의해 데이터 행이 수정된 경우에는 업데이트 충돌이 발생하고 스냅샷 트랜잭션이 종료됩니다.If the data row has been modified outside of the snapshot transaction, an update conflict occurs and the snapshot transaction is terminated. SQL Server 데이터베이스 엔진SQL Server Database Engine은 업데이트 충돌을 처리합니다. 업데이트 충돌 검색 기능은 해제할 수 없습니다.The update conflict is handled by the SQL Server 데이터베이스 엔진SQL Server Database Engine and there is no way to disable the update conflict detection.

참고

내부적으로 스냅샷 격리 수준으로 실행되는 업데이트 작업은 스냅샷 트랜잭션이 다음 항목에 액세스할 때는 커밋된 읽기 격리 수준으로 실행됩니다.Update operations running under snapshot isolation internally execute under read committed isolation when the snapshot transaction accesses any of the following:

FOREIGN KEY 제약 조건이 있는 테이블A table with a FOREIGN KEY constraint.

다른 테이블의 FOREIGN KEY 제약 조건에서 참조되는 테이블A table that is referenced in the FOREIGN KEY constraint of another table.

둘 이상의 테이블을 참조하는 인덱싱된 뷰An indexed view referencing more than one table.

그러나 이러한 조건에서도 업데이트 작업은 다른 트랜잭션에 의해 데이터가 수정되지 않았는지 확인합니다.However, even under these conditions the update operation will continue to verify that the data has not been modified by another transaction. 다른 트랜잭션에 의해 데이터가 수정된 경우 스냅샷 트랜잭션에서 업데이트 충돌이 발생하고 종료됩니다.If data has been modified by another transaction, the snapshot transaction encounters an update conflict and is terminated.

동작 요약Behavior in summary

다음 표에서는 행 버전 관리를 사용하는 스냅샷 격리와 커밋된 읽기 격리의 차이점을 요약합니다.The following table summarizes the differences between snapshot isolation and read committed isolation using row versioning.

속성Property 행 버전 관리를 사용하는 커밋된 읽기 격리 수준Read-committed isolation level using row versioning 스냅샷 격리 수준Snapshot isolation level
지원 요구 사항에 따라 ON으로 설정되어야 하는 데이터베이스 옵션The database option that must be set to ON to enable the required support. READ_COMMITTED_SNAPSHOTREAD_COMMITTED_SNAPSHOT ALLOW_SNAPSHOT_ISOLATIONALLOW_SNAPSHOT_ISOLATION
세션에서 특정한 유형의 행 버전 관리를 요청하는 방법How a session requests the specific type of row versioning. 기본 커밋된 읽기 격리 수준을 사용하거나 SET TRANSACTION ISOLATION LEVEL 문을 실행하여 READ COMMITTED 격리 수준을 지정합니다.Use the default read-committed isolation level, or run the SET TRANSACTION ISOLATION LEVEL statement to specify the READ COMMITTED isolation level. 이 작업은 트랜잭션이 시작된 후에 수행할 수 있습니다.This can be done after the transaction starts. 트랜잭션이 시작되기 전에 SET TRANSACTION ISOLATION LEVEL 문을 실행하여 SNAPSHOT 격리 수준을 지정해야 합니다.Requires the execution of SET TRANSACTION ISOLATION LEVEL to specify the SNAPSHOT isolation level before the start of the transaction.
문에서 읽는 데이터의 버전The version of data read by statements. 각 문이 시작되기 전에 커밋된 모든 데이터All data that was committed before the start of each statement. 각 트랜잭션이 시작되기 전에 커밋된 모든 데이터All data that was committed before the start of each transaction.
업데이트 처리 방법How updates are handled. 행 버전을 실제 데이터로 변환하여 업데이트할 행을 선택하고 선택한 데이터 행에 업데이트 잠금을 사용합니다.Reverts from row versions to actual data to select rows to update and uses update locks on the data rows selected. 수정할 실제 데이터 행에 대해 배타적 잠금을 획득합니다.Acquires exclusive locks on actual data rows to be modified. 업데이트 충돌 검색은 사용되지 않습니다.No update conflict detection. 행 버전을 사용하여 업데이트할 행을 선택합니다.Uses row versions to select rows to update. 수정할 실제 데이터 행에 대해 배타적 잠금을 획득하려고 시도합니다. 데이터가 다른 트랜잭션에 의해 이미 수정된 경우에는 업데이트 충돌이 발생하며 스냅샷 트랜잭션이 종료됩니다.Tries to acquire an exclusive lock on the actual data row to be modified, and if the data has been modified by another transaction, an update conflict occurs and the snapshot transaction is terminated.
업데이트 충돌 검색Update conflict detection. 없음None. 통합 지원되며Integrated support. 해제할 수 없습니다.Cannot be disabled.

행 버전 관리 리소스 사용Row Versioning resource usage

행 버전 관리 프레임워크는 SQL ServerSQL Server의 다음 기능을 지원합니다.The row versioning framework supports the following features available in SQL ServerSQL Server:

  • 트리거Triggers
  • MARS(Multiple Active Results Sets)Multiple Active Results Sets (MARS)
  • 온라인 인덱싱Online indexing

또한 행 버전 관리 프레임워크는 다음 행 버전 관리 기반 트랜잭션 격리 수준을 지원합니다. 이러한 격리 수준은 기본적으로 설정되지 않습니다.The row versioning framework also supports the following row versioning-based transaction isolation levels, which by default are not enabled:

  • READ_COMMITTED_SNAPSHOT 데이터베이스 옵션이 ON이면 READ_COMMITTED 트랜잭션이 행 버전 관리를 사용하여 문 수준의 읽기 일관성을 제공합니다.When the READ_COMMITTED_SNAPSHOT database option is ON, READ_COMMITTED transactions provide statement-level read consistency using row versioning.
  • ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션이 ON이면 SNAPSHOT 트랜잭션이 행 버전 관리를 사용하여 트랜잭션 수준의 읽기 일관성을 제공합니다.When the ALLOW_SNAPSHOT_ISOLATION database option is ON, SNAPSHOT transactions provide transaction-level read consistency using row versioning.

행 버전 관리 기반 격리 수준을 이용하면 읽기 작업에 대해 공유 잠금을 사용하지 않아도 되므로 트랜잭션에 의해 확보되는 잠금 수가 줄어듭니다.Row versioning-based isolation levels reduce the number of locks acquired by transaction by eliminating the use of shared locks on read operations. 결과적으로 잠금 관리에 사용되는 리소스가 줄어 시스템 성능이 향상됩니다.This increases system performance by reducing the resources used to manage locks. 또한 다른 트랜잭션에 의해 확보된 잠금으로 인해 트랜잭션이 차단되는 횟수도 줄어 성능이 한층 더 향상됩니다.Performance is also increased by reducing the number of times a transaction is blocked by locks acquired by other transactions.

행 버전 관리 기반 격리 수준을 이용하면 데이터 수정에 필요한 리소스가 늘어납니다.Row versioning-based isolation levels increase the resources needed by data modifications. 이 옵션을 설정하면 데이터베이스의 모든 데이터 수정에 대해 버전이 지정됩니다.Enabling these options causes all data modifications for the database to be versioned. 행 버전 관리 기반 격리를 사용하는 활성 트랜잭션이 없는 경우에도 수정 전에 데이터의 복사본이 tempdb에 저장됩니다.A copy of the data before modification is stored in tempdb even when there are no active transactions using row versioning-based isolation. 수정 후의 데이터에는 tempdb에 저장된 버전 지정 데이터에 대한 포인터가 포함됩니다.The data after modification includes a pointer to the versioned data stored in tempdb. 큰 개체의 경우 개체의 변경된 부분만 tempdb에 복사됩니다.For large objects, only part of the object that changed is copied to tempdb.

TempDB의 사용된 공간Space used in TempDB

SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스의 tempdb에는 해당 인스턴스의 모든 데이터베이스에 대해 생성된 행 버전을 보유할 수 있는 공간이 있어야 합니다.For each instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine, tempdb must have enough space to hold the row versions generated for every database in the instance. 데이터베이스 관리자는 TempDB에 버전 저장소를 포함할 수 있는 충분한 공간이 있는지를 확인해야 합니다.The database administrator must ensure that TempDB has ample space to support the version store. TempDB에는 다음의 두 버전 저장소가 있습니다.There are two version stores in TempDB:

  • 온라인 인덱스 작성 버전 저장소는 모든 데이터베이스의 온라인 인덱스 작성에 사용됩니다.The online index build version store is used for online index builds in all databases.
  • 공용 버전 저장소는 모든 데이터베이스의 다른 모든 데이터 수정 작업에 사용됩니다.The common version store is used for all other data modification operations in all databases.

활성 트랜잭션에서 행 버전에 액세스해야 하는 동안에는 행 버전이 저장되어야 합니다.Row versions must be stored for as long as an active transaction needs to access it. 1분마다 백그라운드 스레드가 필요 없게 된 행 버전을 제거하여 TempDB에서 공간을 비웁니다.Once every minute, a background thread removes row versions that are no longer needed and frees up the version space in TempDB. 다음 중 하나에 해당될 경우 장기 실행 트랜잭션은 버전 저장소의 공간이 해제되지 않도록 합니다.A long-running transaction prevents space in the version store from being released if it meets any of the following conditions:

  • 행 버전 관리 기반 격리를 사용합니다.It uses row versioning-based isolation.
  • 트리거, MARS 또는 온라인 인덱스 작성 작업을 사용합니다.It uses triggers, MARS, or online index build operations.
  • 행 버전을 생성합니다.It generates row versions.

참고

트랜잭션 내부에서 트리거를 호출하면 해당 트리거에 의해 생성된 행 버전은 트리거가 완료된 후 행 버전이 더 이상 필요하지 않아도 트랜잭션이 끝날 때까지 유지됩니다.When a trigger is invoked inside a transaction, the row versions created by the trigger are maintained until the end of the transaction, even though the row versions are no longer needed after the trigger completes. 이는 행 버전 관리를 사용하는 커밋된 읽기 트랜잭션에도 적용됩니다.This also applies to read-committed transactions that use row versioning. 이 유형의 트랜잭션에서는 트랜잭션의 각 문에 대해서만 데이터베이스의 트랜잭션 뷰가 일치해야 하므로With this type of transaction, a transactionally consistent view of the database is needed only for each statement in the transaction. 문이 완료된 후에는 트랜잭션의 문에 대해 생성된 행 버전이 필요하지 않습니다.This means that the row versions created for a statement in the transaction are no longer needed after the statement completes. 그러나 트랜잭션의 각 문에 의해 생성된 행 버전은 트랜잭션이 완료될 때까지 유지됩니다.However, row versions created by each statement in the transaction are maintained until the transaction completes.

TempDB의 공간이 부족하면 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 버전 저장소를 강제로 축소합니다.When TempDB runs out of space, the SQL Server 데이터베이스 엔진SQL Server Database Engine forces the version stores to shrink. 축소하는 동안, 아직 행 버전을 생성하지 않은 트랜잭션 중 장기 실행 트랜잭션은 교착 상태가 발생한 것으로 표시됩니다.During the shrink process, the longest running transactions that have not yet generated row versions are marked as victims. 오류 로그에는 교착 상태가 발생한 각 트랜잭션에 대해 메시지 3967이 생성됩니다.A message 3967 is generated in the error log for each victim transaction. 교착 상태가 발생한 것으로 표시된 트랜잭션은 버전 저장소의 행 버전을 더 이상 읽을 수 없습니다.If a transaction is marked as a victim, it can no longer read the row versions in the version store. 행 버전을 읽으려고 하면 메시지 3966이 생성되고 트랜잭션이 롤백됩니다.When it attempts to read row versions, message 3966 is generated and the transaction is rolled back. 축소하는 데 성공하면 tempdb에서 공간을 사용할 수 있게 됩니다.If the shrinking process succeeds, space becomes available in tempdb. 그렇지 않으면 tempdb의 공간이 부족해지고 다음과 같은 상황이 발생합니다.Otherwise, tempdb runs out of space and the following occurs:

  • 쓰기 작업이 계속 실행되지만 버전을 생성하지 않습니다.Write operations continue to execute but do not generate versions. 오류 로그에 정보 메시지(3959)가 나타납니다. 데이터를 기록한 트랜잭션은 영향을 받지 않습니다.An information message (3959) appears in the error log, but the transaction that writes data is not affected.

  • tempdb의 완전 롤백으로 인해 생성되지 않은 행 버전에 액세스하려고 하는 트랜잭션은 오류 3958과 함께 종료됩니다.Transactions that attempt to access row versions that were not generated because of a tempdb full rollback terminate with an error 3958.

데이터 행의 공간 사용량Space used in data rows

각 데이터베이스 행의 행 끝에서 최대 14바이트를 사용하여 행 버전 관리 정보를 저장할 수 있습니다.Each database row may use up to 14 bytes at the end of the row for row versioning information. 행 버전 관리 정보에는 버전을 커밋한 트랜잭션의 트랜잭션 시퀀스 번호와 버전이 지정된 행에 대한 포인터가 포함됩니다.The row versioning information contains the transaction sequence number of the transaction that committed the version and the pointer to the versioned row. 이 14바이트는 다음과 같은 조건에서 행이 처음 수정될 때 또는 새 행이 삽입될 때 추가됩니다.These 14 bytes are added the first time the row is modified, or when a new row is inserted, under any of these conditions:

  • READ_COMMITTED_SNAPSHOT 또는 ALLOW_SNAPSHOT_ISOLATION 옵션은 ON입니다.READ_COMMITTED_SNAPSHOT or ALLOW_SNAPSHOT_ISOLATION options are ON.
  • 테이블에 트리거가 있습니다.The table has a trigger.
  • MARS(Multiple Active Results Sets)를 사용하고 있습니다.Multiple Active Results Sets (MARS) is being used.
  • 테이블에서 현재 온라인 인덱스 작성 작업이 실행되고 있습니다.Online index build operations are currently running on the table.

이 14바이트는 다음과 같은 조건에서 행이 처음 수정될 때 데이터베이스 행에서 제거됩니다.These 14 bytes are removed from the database row the first time the row is modified under all of these conditions:

  • READ_COMMITTED_SNAPSHOTALLOW_SNAPSHOT_ISOLATION 옵션은 OFF입니다.READ_COMMITTED_SNAPSHOT and ALLOW_SNAPSHOT_ISOLATION options are OFF.
  • 테이블에 트리거가 없습니다.The trigger no longer exists on the table.
  • MARS를 사용하고 있지 않습니다.MARS is not being used.
  • 현재 온라인 인덱스 작성 작업이 실행되고 있지 않습니다.Online index build operations are not currently running.

행 버전 관리 기능을 사용하는 경우에는 데이터베이스 행당 14바이트를 사용할 수 있도록 데이터베이스에 더 많은 디스크 공간을 할당해야 할 수 있습니다.If you use any of the row versioning features, you might need to allocate additional disk space for the database to accommodate the 14 bytes per database row. 행 버전 관리 정보를 추가하면 인덱스 페이지가 분할되거나 현재 페이지에 사용 가능한 공간이 충분하지 않은 경우에는 새 데이터 페이지가 할당될 수 있습니다.Adding the row versioning information can cause index page splits or the allocation of a new data page if there is not enough space available on the current page. 예를 들어 평균 행 길이가 100바이트인 경우 14바이트를 추가하면 기존 테이블이 최대 14% 증가할 수 있습니다.For example, if the average row length is 100 bytes, the additional 14 bytes cause an existing table to grow up to 14 percent.

채우기 비율을 낮추면 인덱스 페이지의 조각화를 방지하거나 줄일 수 있습니다.Decreasing the fill factor might help to prevent or decrease fragmentation of index pages. 테이블 또는 뷰의 데이터와 인덱스에 대한 조각화 정보를 보려면 sys.dm_db_index_physical_stats를 사용합니다.To view fragmentation information for the data and indexes of a table or view, you can use sys.dm_db_index_physical_stats.

큰 개체의 공간 사용량Space used in Large Objects

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 최대 2GB의 큰 문자열을 저장할 수 있는 6개의 데이터 형식을 지원합니다. 6개의 데이터 형식은 nvarchar(max), varchar(max), varbinary(max), ntext, textimage입니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine supports six data types that can hold large strings up to 2 gigabytes (GB) in length: nvarchar(max), varchar(max), varbinary(max), ntext, text, and image. 이러한 데이터 형식을 사용하여 저장된 큰 문자열은 데이터 행에 연결된 일련의 데이터 조각에 저장됩니다.Large strings stored using these data types are stored in a series of data fragments that are linked to the data row. 행 버전 관리 정보는 큰 문자열이 저장된 각 조각에 저장됩니다.Row versioning information is stored in each fragment used to store these large strings. 데이터 조각은 테이블의 큰 개체에만 사용되는 페이지의 모음입니다.Data fragments are a collection of pages dedicated to large objects in a table.

데이터베이스에 새로 큰 값이 추가될 때 조각당 최대 8040바이트의 데이터가 할당됩니다.As new large values are added to a database, they are allocated using a maximum of 8040 bytes of data per fragment. 이전 버전의 SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 조각당 최대 8080바이트의 ntext, text 또는 image 데이터를 저장했습니다.Earlier versions of the SQL Server 데이터베이스 엔진SQL Server Database Engine stored up to 8080 bytes of ntext, text, or image data per fragment.

이전 버전의 ntext에서 text로 데이터베이스를 업그레이드한 경우에는 행 버전 관리 정보를 저장할 공간을 만들기 위해 기존 image, SQL ServerSQL ServerSQL ServerSQL Server LOB(Large Object) 데이터가 업데이트되지 않습니다.Existing ntext, text, and image large object (LOB) data is not updated to make space for the row versioning information when a database is upgraded to SQL ServerSQL Server from an earlier version of SQL ServerSQL Server. 그러나 LOB 데이터가 처음 수정될 때는 버전 관리 정보를 스토리지할 수 있도록 데이터가 동적으로 업그레이드됩니다.However, the first time the LOB data is modified, it is dynamically upgraded to enable storage of versioning information. 이는 행 버전이 생성되지 않은 경우에도 마찬가지입니다.This will happen even if row versions are not generated. LOB 데이터가 업그레이드된 후에는 조각당 저장되는 최대 바이트 수가 8080바이트에서 8040바이트로 줄어듭니다.After the LOB data is upgraded, the maximum number of bytes stored per fragment is reduced from 8080 bytes to 8040 bytes. 업그레이드 프로세스에서는 LOB 값을 삭제하고 동일한 값을 다시 삽입합니다.The upgrade process is equivalent to deleting the LOB value and reinserting the same value. 1바이트만 수정되더라도 LOB 데이터가 업그레이드됩니다.The LOB data is upgraded even if only one byte is modified. 이 작업은 각 ntext, text 또는 image 열에 대해 한 번 수행되지만 LOB 데이터의 크기에 따라 각 작업 수행 시 대량의 페이지 할당 및 I/O 작업이 발생할 수 있습니다.This is a one-time operation for each ntext, text, or image column, but each operation may generate a large amount of page allocations and I/O activity depending upon the size of the LOB data. 수정 내용 전체가 로깅되는 경우에는 대량의 로깅 작업이 발생할 수도 있습니다.It may also generate a large amount of logging activity if the modification is fully logged. 데이터베이스 복구 모드를 FULL로 설정하지 않으면 WRITETEXT와 UPDATETEXT 작업에서 최소한의 정보만 로깅합니다.WRITETEXT and UPDATETEXT operations are minimally logged if database recovery mode is not set to FULL.

nvarchar(max), varchar(max)varbinary(max) 데이터 형식은 이전 버전의 SQL ServerSQL Server에서는 사용할 수 없으므로The nvarchar(max), varchar(max), and varbinary(max) data types are not available in earlier versions of SQL ServerSQL Server. 업그레이드 문제가 발생하지 않습니다.Therefore, they have no upgrade issues.

이 요구 사항을 충족하는 충분한 디스크 공간을 할당해야 합니다.Enough disk space should be allocated to accommodate this requirement.

행 버전 관리 및 버전 저장소 모니터링Monitoring Row Versioning and the Version Store

행 버전 관리, 버전 저장소 및 스냅샷 격리 프로세스의 성능과 문제를 모니터링하기 위해 SQL ServerSQL Server에서는 DMV(동적 관리 뷰) 및 Windows 시스템 모니터의 성능 카운터 형태로 도구를 제공합니다.For monitoring row versioning, version store, and snapshot isolation processes for performance and problems, SQL ServerSQL Server provides tools in the form of Dynamic Management Views (DMVs) and performance counters in Windows System Monitor.

DMVDMVs

다음 DMV는 tempdb와 버전 저장소 및 행 버전 관리를 사용하는 트랜잭션의 현재 상태에 대한 정보를 제공합니다.The following DMVs provide information about the current system state of tempdb and the version store, as well as transactions using row versioning.

sys.dm_db_file_space_usage.sys.dm_db_file_space_usage. 데이터베이스의 각 파일에 대한 공간 사용량 정보를 반환합니다.Returns space usage information for each file in the database. 자세한 내용은 sys.dm_db_file_space_usage (Transact-SQL)를 참조하세요.For more information, see sys.dm_db_file_space_usage (Transact-SQL).

sys.dm_db_session_space_usage.sys.dm_db_session_space_usage. 데이터베이스에서 발생하는 세션별 페이지 할당 및 할당 취소 작업을 반환합니다.Returns page allocation and deallocation activity by session for the database. 자세한 내용은 sys.dm_db_session_space_usage(Transact-SQL)를 참조하세요.For more information, see sys.dm_db_session_space_usage (Transact-SQL).

sys.dm_db_task_space_usage.sys.dm_db_task_space_usage. 데이터베이스에서 발생하는 태스크별로 페이지 할당 및 할당 취소 작업을 반환합니다.Returns page allocation and deallocation activity by task for the database. 자세한 내용은 sys.dm_db_task_space_usage(Transact-SQL)를 참조하세요.For more information, see sys.dm_db_task_space_usage (Transact-SQL).

sys.dm_tran_top_version_generators.sys.dm_tran_top_version_generators. 버전 저장소의 버전 대부분을 생성하는 개체에 대한 가상 테이블을 반환합니다.Returns a virtual table for the objects producing the most versions in the version store. 256개의 집계 레코드 길이를 database_id 및 rowset_id에 따라 그룹화합니다.It groups the top 256 aggregated record lengths by database_id and rowset_id. 이 함수를 사용하면 버전 저장소를 가장 많이 사용하는 소비자를 찾을 수 있습니다.Use this function to find the largest consumers of the version store. 자세한 내용은 sys.dm_tran_top_version_generators(Transact-SQL)를 참조하세요.For more information, see sys.dm_tran_top_version_generators (Transact-SQL).

sys.dm_tran_version_store.sys.dm_tran_version_store. 공용 버전 저장소의 모든 버전 레코드를 표시하는 가상 테이블을 반환합니다.Returns a virtual table that displays all version records in the common version store. 자세한 내용은 sys.dm_tran_version_store(Transact-SQL)를 참조하세요.For more information, see sys.dm_tran_version_store (Transact-SQL).

sys.dm_tran_version_store_space_usage.sys.dm_tran_version_store_space_usage. 각 데이터베이스에 대한 버전 저장소 레코드에서 사용되는 tempdb의 총 공간을 표시하는 가상 테이블을 반환합니다.Returns a virtual table that displays the total space in tempdb used by version store records for each database. 자세한 내용은 sys.dm_tran_version_store_space_usage(Transact-SQL)를 참조하세요.For more information, see sys.dm_tran_version_store_space_usage (Transact-SQL).

참고

sys.dm_tran_top_version_generators와 sys.dm_tran_version_store 함수는 버전 저장소 전체를 쿼리하므로 버전 저장소의 크기가 클 경우에는 실행하는 데 비용이 많이 들 수 있습니다.sys.dm_tran_top_version_generators and sys.dm_tran_version_store are potentially very expensive functions to run, since both query the entire version store, which could be very large.
sys.dm_tran_version_store_space_usage는 개별 버전 저장소 레코드를 탐색하지 않고 데이터베이스 당 tempdb에서 사용되는 집계된 버전 저장소 공간을 반환하므로 실행하기 효율적이고 비용이 많이 들지 않습니다.sys.dm_tran_version_store_space_usage is efficient and not expensive to run, as it does not navigate through individual version store records and returns aggregated version store space consumed in tempdb per database

sys.dm_tran_active_snapshot_database_transactions.sys.dm_tran_active_snapshot_database_transactions. 행 버전 관리를 사용하는 SQL ServerSQL Server 인스턴스 내의 모든 데이터베이스에 있는 전체 활성 트랜잭션에 대한 가상 테이블을 반환합니다.Returns a virtual table for all active transactions in all databases within the SQL ServerSQL Server instance that use row versioning. 시스템 트랜잭션은 이 DMV에 나타나지 않습니다.System transactions do not appear in this DMV. 자세한 내용은 sys.dm_tran_active_snapshot_database_transactions(Transact-SQL)을 참조하세요.For more information, see sys.dm_tran_active_snapshot_database_transactions (Transact-SQL).

sys.dm_tran_transactions_snapshot.sys.dm_tran_transactions_snapshot. 각 트랜잭션에서 사용한 스냅샷을 표시하는 가상 테이블을 반환합니다.Returns a virtual table that displays snapshots taken by each transaction. 스냅샷에는 행 버전 관리를 사용하는 활성 트랜잭션의 시퀀스 번호가 포함됩니다.The snapshot contains the sequence number of the active transactions that use row versioning. 자세한 내용은 sys.dm_tran_transactions_snapshot(Transact-SQL)을 참조하세요.For more information, see sys.dm_tran_transactions_snapshot (Transact-SQL).

sys.dm_tran_current_transaction.sys.dm_tran_current_transaction. 현재 세션에 있는 트랜잭션의 행 버전 관리 관련 상태 정보를 표시하는 단일 행을 반환합니다.Returns a single row that displays row versioning-related state information of the transaction in the current session. 자세한 내용은 sys.dm_tran_current_transaction(Transact-SQL)을 참조하세요.For more information, see sys.dm_tran_current_transaction (Transact-SQL).

sys.dm_tran_current_snapshot.sys.dm_tran_current_snapshot. 현재 스냅샷 격리 트랜잭션이 시작될 때의 모든 활성 트랜잭션을 표시하는 가상 테이블을 반환합니다.Returns a virtual table that displays all active transactions at the time the current snapshot isolation transaction starts. 현재 트랜잭션에서 스냅샷 격리를 사용중인 경우 이 함수는 행을 반환하지 않습니다.If the current transaction is using snapshot isolation, this function returns no rows. sys.dm_tran_current_snapshot이 현재 스냅샷에 대한 활성 트랜잭션만 반환한다는 점을 제외하고 sys.dm_tran_transactions_snapshot과 비슷합니다.sys.dm_tran_current_snapshot is similar to sys.dm_tran_transactions_snapshot, except that it returns only the active transactions for the current snapshot. 자세한 내용은 sys.dm_tran_current_snapshot(Transact-SQL)을 참조하세요.For more information, see sys.dm_tran_current_snapshot (Transact-SQL).

성능 카운터Performance Counters

SQL ServerSQL Server 성능 카운터는 SQL ServerSQL Server 프로세스의 영향을 받는 시스템 성능에 대한 정보를 제공합니다.performance counters provide information about the system performance impacted by SQL ServerSQL Server processes. 다음 성능 카운터는 tempdb와 버전 저장소 및 행 버전 관리를 사용하는 트랜잭션을 모니터링합니다.The following performance counters monitor tempdb and the version store, as well as transactions using row versioning. 이러한 성능 카운터는 SQLServer:Transactions 성능 개체에 포함되어 있습니다.The performance counters are contained in the SQLServer:Transactions performance object.

Free Space in tempdb (KB) .Free Space in tempdb (KB). tempdb 데이터베이스의 사용 가능한 공간(KB)을 모니터링합니다.Monitors the amount, in kilobytes (KB), of free space in the tempdb database. tempdb에는 스냅샷 격리를 지원하는 버전 저장소를 처리하기에 충분한 공간이 있어야 합니다.There must be enough free space in tempdb to handle the version store that supports snapshot isolation.

다음 공식을 사용하여 버전 저장소의 예상 크기를 대략적으로 계산할 수 있습니다.The following formula provides a rough estimate of the size of the version store. 장기 실행 트랜잭션의 경우 생성 및 정리 속도를 모니터링하여 버전 저장소의 예상 최대 크기를 결정하면 유용합니다.For long-running transactions, it may be useful to monitor the generation and cleanup rate to estimate the maximum size of the version store.

[공용 버전 저장소의 크기] = 2 * [분당 생성되는 버전 저장소 데이터] * [트랜잭션의 최장 실행 시간(분)][size of common version store] = 2 * [version store data generated per minute] * [longest running time (minutes) of the transaction]

트랜잭션의 최장 실행 시간에는 온라인 인덱스 작성이 포함되지 않습니다.The longest running time of transactions should not include online index builds. 큰 테이블의 경우 온라인 인덱스 작성 작업에 많은 시간이 소요되므로 이 작업은 별도의 버전 저장소를 사용합니다.Because these operations may take a long time on very large tables, online index builds use a separate version store. 온라인 인덱스 작성 버전 저장소의 크기는 온라인 인덱스 작성을 수행하는 동안 모든 인덱스를 포함하여 테이블에서 수정된 전체 데이터 양과 거의 같습니다.The approximate size of the online index build version store equals the amount of data modified in the table, including all indexes, while the online index build is active.

Version Store Size (KB) .Version Store Size (KB). 모든 버전 저장소의 크기(KB)를 모니터링합니다.Monitors the size in KB of all version stores. 이 정보를 통해 tempdb 데이터베이스의 버전 저장소에 필요한 공간을 결정할 수 있습니다.This information helps determine the amount of space needed in the tempdb database for the version store. 이 카운터를 지속적으로 모니터링하면 tempdb에 필요한 추가 공간을 예측할 수 있습니다.Monitoring this counter over a period of time provides a useful estimate of additional space needed for tempdb.

Version Generation rate (KB/s).Version Generation rate (KB/s). 모든 버전 저장소의 버전 생성 속도(KB/초)를 모니터링합니다.Monitors the version generation rate in KB per second in all version stores.

Version Cleanup rate (KB/s).Version Cleanup rate (KB/s). 모든 버전 저장소의 버전 정리 속도(KB/초)를 모니터링합니다.Monitors the version cleanup rate in KB per second in all version stores.

참고

Version Generation rate (KB/s) 및 Version Cleanup rate (KB/s)에서 제공하는 정보를 통해 tempdb에 필요한 공간을 예측할 수 있습니다.Information from Version Generation rate (KB/s) and Version Cleanup rate (KB/s) can be used to predict tempdb space requirements.

Version Store unit count.Version Store unit count. 버전 저장소 단위 수를 모니터링합니다.Monitors the count of version store units.

Version Store unit creation.Version Store unit creation. 인스턴스가 시작된 이후 행 버전을 저장하기 위해 생성된 버전 저장소 단위의 총 수를 모니터링합니다.Monitors the total number of version store units created to store row versions since the instance was started.

Version Store unit truncation.Version Store unit truncation. 인스턴스가 시작된 이후 잘린 버전 저장소 단위의 총 수를 모니터링합니다.Monitors the total number of version store units truncated since the instance was started. SQL ServerSQL Server에서 버전 저장소 단위에 저장된 버전 행이 활성 트랜잭션을 실행하는 데 불필요하다고 결정하면 버전 저장소 단위가 잘립니다.A version store unit is truncated when SQL ServerSQL Server determines that none of the version rows stored in the version store unit are needed to run active transactions.

Update conflict ratio.Update conflict ratio. 총 업데이트 스냅샷 트랜잭션 중 업데이트 충돌이 있는 업데이트 스냅샷 트랜잭션의 비율을 모니터링합니다.Monitors the ratio of update snapshot transaction that have update conflicts to the total number of update snapshot transactions.

Longest Transaction Running Time.Longest Transaction Running Time. 행 버전 관리를 사용하는 트랜잭션의 가장 긴 실행 시간(초)을 모니터링합니다.Monitors the longest running time in seconds of any transaction using row versioning. 이 정보를 사용하면 특별한 이유 없이 오래 실행되는 트랜잭션이 있는지를 확인할 수 있습니다.This can be used to determine if any transaction is running for an unreasonable amount of time.

트랜잭션.Transactions. 활성 트랜잭션의 총 수를 모니터링합니다.Monitors the total number of active transactions. 시스템 트랜잭션은 포함되지 않습니다.This does not include system transactions.

Snapshot Transactions.Snapshot Transactions. 활성 스냅샷 트랜잭션의 총 수를 모니터링합니다.Monitors the total number of active snapshot transactions.

Update Snapshot Transactions.Update Snapshot Transactions. 업데이트 작업을 수행하는 활성 스냅샷 트랜잭션의 총 수를 모니터링합니다.Monitors the total number of active snapshot transactions that perform update operations.

NonSnapshot Version Transactions.NonSnapshot Version Transactions. 버전 레코드를 생성하는 활성 비스냅샷 트랜잭션의 총 수를 모니터링합니다.Monitors the total number of active non-snapshot transactions that generate version records.

참고

Update Snapshot Transactions와 NonSnapshot Version Transactions의 합은 버전 생성에 참여하는 트랜잭션의 총 수를 나타냅니다.The sum of Update Snapshot Transactions and NonSnapshot Version Transactions represents the total number of transactions that participate in version generation. Snapshot Transactions와 Update Snapshot Transactions 값의 차이를 보고 읽기 전용 스냅샷 트랜잭션의 수를 알 수 있습니다.The difference of Snapshot Transactions and Update Snapshot Transactions reports the number of read-only snapshot transactions.

행 버전 관리 기반 격리 수준 예Row Versioning-based Isolation Level Example

다음 예에서는 스냅샷 격리 트랜잭션과 행 버전 관리를 사용하는 커밋된 읽기 트랜잭션 동작의 차이를 보여 줍니다.The following examples show the differences in behavior between snapshot isolation transactions and read-committed transactions that use row versioning.

A.A. 스냅샷 격리 작업Working with snapshot isolation

이 예에서는 스냅샷 격리에서 실행되는 트랜잭션이 다른 트랜잭션에서 수정한 데이터를 읽습니다.In this example, a transaction running under snapshot isolation reads data that is then modified by another transaction. 스냅샷 트랜잭션은 다른 트랜잭션에서 실행하는 업데이트 작업을 차단하지 않으며 데이터 수정을 무시하고 계속 버전이 지정된 행에서 데이터를 읽습니다.The snapshot transaction does not block the update operation executed by the other transaction, and it continues to read data from the versioned row, ignoring the data modification. 그러나 스냅샷 트랜잭션이 다른 트랜잭션에서 이미 수정한 데이터를 수정할 경우 스냅샷 트랜잭션은 오류를 생성하고 종료됩니다.However, when the snapshot transaction attempts to modify the data that has already been modified by the other transaction, the snapshot transaction generates an error and is terminated.

세션 1:On session 1:

USE AdventureWorks2016;  
GO  
  
-- Enable snapshot isolation on the database.  
ALTER DATABASE AdventureWorks2016  
    SET ALLOW_SNAPSHOT_ISOLATION ON;  
GO  
  
-- Start a snapshot transaction  
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;  
GO  
  
BEGIN TRANSACTION;  
    -- This SELECT statement will return  
    -- 48 vacation hours for the employee.  
    SELECT BusinessEntityID, VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  

세션 2:On session 2:

USE AdventureWorks2016;  
GO  
  
-- Start a transaction.  
BEGIN TRANSACTION;  
    -- Subtract a vacation day from employee 4.  
    -- Update is not blocked by session 1 since  
    -- under snapshot isolation shared locks are  
    -- not requested.  
    UPDATE HumanResources.Employee  
        SET VacationHours = VacationHours - 8  
        WHERE BusinessEntityID = 4;  
  
    -- Verify that the employee now has 40 vacation hours.  
    SELECT VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  

세션 1:On session 1:

    -- Reissue the SELECT statement - this shows  
    -- the employee having 48 vacation hours.  The  
    -- snapshot transaction is still reading data from  
    -- the versioned row.  
    SELECT BusinessEntityID, VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  

세션 2:On session 2:

-- Commit the transaction; this commits the data  
-- modification.  
COMMIT TRANSACTION;  
GO  

세션 1:On session 1:

    -- Reissue the SELECT statement - this still   
    -- shows the employee having 48 vacation hours  
    -- even after the other transaction has committed  
    -- the data modification.  
    SELECT BusinessEntityID, VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  
  
    -- Because the data has been modified outside of the  
    -- snapshot transaction, any further data changes to   
    -- that data by the snapshot transaction will cause   
    -- the snapshot transaction to fail. This statement   
    -- will generate a 3960 error and the transaction will   
    -- terminate.  
    UPDATE HumanResources.Employee  
        SET SickLeaveHours = SickLeaveHours - 8  
        WHERE BusinessEntityID = 4;  
  
-- Undo the changes to the database from session 1.   
-- This will not undo the change from session 2.  
ROLLBACK TRANSACTION  
GO  

B.B. 행 버전 관리를 사용한 커밋된 읽기 작업Working with read-committed using row versioning

이 예에서 행 버전 관리를 사용하는 커밋된 읽기 트랜잭션은 다른 트랜잭션과 동시에 실행됩니다.In this example, a read-committed transaction using row versioning runs concurrently with another transaction. 커밋된 읽기 트랜잭션은 스냅샷 트랜잭션과 다르게 동작합니다.The read-committed transaction behaves differently than a snapshot transaction. 스냅샷 트랜잭션과 마찬가지로 커밋된 읽기 트랜잭션도 다른 트랜잭션이 데이터를 수정한 이후에 버전이 지정된 행을 읽습니다.Like a snapshot transaction, the read-committed transaction will read versioned rows even after the other transaction has modified data. 그러나 커밋된 읽기 트랜잭션은 스냅샷 트랜잭션과 달리 다음 작업을 수행합니다.However, unlike a snapshot transaction, the read-committed transaction will:

  • 다른 트랜잭션이 데이터 변경 내용을 커밋한 이후에 수정한 데이터를 읽습니다.Read the modified data after the other transaction commits the data changes.
  • 스냅샷 트랜잭션과 달리 다른 트랜잭션에서 수정한 데이터를 업데이트할 수 있습니다.Be able to update the data modified by the other transaction where the snapshot transaction could not.

세션 1:On session 1:

USE AdventureWorks2016;  -- Or any earlier version of the AdventureWorks database.  
GO  
  
-- Enable READ_COMMITTED_SNAPSHOT on the database.  
-- For this statement to succeed, this session  
-- must be the only connection to the AdventureWorks2016  
-- database.  
ALTER DATABASE AdventureWorks2016  
    SET READ_COMMITTED_SNAPSHOT ON;  
GO  
  
-- Start a read-committed transaction  
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;  
GO  
  
BEGIN TRANSACTION;  
    -- This SELECT statement will return  
    -- 48 vacation hours for the employee.  
    SELECT BusinessEntityID, VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  

세션 2:On session 2:

USE AdventureWorks2016;  
GO  
  
-- Start a transaction.  
BEGIN TRANSACTION;  
    -- Subtract a vacation day from employee 4.  
    -- Update is not blocked by session 1 since  
    -- under read-committed using row versioning shared locks are  
    -- not requested.  
    UPDATE HumanResources.Employee  
        SET VacationHours = VacationHours - 8  
        WHERE BusinessEntityID = 4;  
  
    -- Verify that the employee now has 40 vacation hours.  
    SELECT VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  

세션 1:On session 1:

    -- Reissue the SELECT statement - this still shows  
    -- the employee having 48 vacation hours.  The  
    -- read-committed transaction is still reading data   
    -- from the versioned row and the other transaction   
    -- has not committed the data changes yet.  
    SELECT BusinessEntityID, VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  

세션 2:On session 2:

-- Commit the transaction.  
COMMIT TRANSACTION;  
GO  

세션 1:On session 1:

    -- Reissue the SELECT statement which now shows the   
    -- employee having 40 vacation hours.  Being   
    -- read-committed, this transaction is reading the   
    -- committed data. This is different from snapshot  
    -- isolation which reads from the versioned row.  
    SELECT BusinessEntityID, VacationHours  
        FROM HumanResources.Employee  
        WHERE BusinessEntityID = 4;  
  
    -- This statement, which caused the snapshot transaction   
    -- to fail, will succeed with read-committed using row versioning.  
    UPDATE HumanResources.Employee  
        SET SickLeaveHours = SickLeaveHours - 8  
        WHERE BusinessEntityID = 4;  
  
-- Undo the changes to the database from session 1.   
-- This will not undo the change from session 2.  
ROLLBACK TRANSACTION;  
GO  

행 버전 관리 기반 격리 수준 설정Enabling Row Versioning-Based Isolation Levels

데이터베이스 관리자는 ALTER DATABASE 문에서 READ_COMMITTED_SNAPSHOTALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 사용하여 행 버전 관리에 대한 데이터베이스 수준 설정을 제어합니다.Database administrators control the database-level settings for row versioning by using the READ_COMMITTED_SNAPSHOT and ALLOW_SNAPSHOT_ISOLATION database options in the ALTER DATABASE statement.

READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 ON으로 설정하면 이 옵션을 지원하는 메커니즘이 즉시 활성화됩니다.When the READ_COMMITTED_SNAPSHOT database option is set ON, the mechanisms used to support the option are activated immediately. READ_COMMITTED_SNAPSHOT 옵션을 설정할 때는 ALTER DATABASE 명령을 실행하는 연결만 데이터베이스에서 허용됩니다.When setting the READ_COMMITTED_SNAPSHOT option, only the connection executing the ALTER DATABASE command is allowed in the database. ALTER DATABASE 명령 실행이 완료될 때까지 데이터베이스에서 다른 열린 연결이 없어야 합니다.There must be no other open connection in the database until ALTER DATABASE is complete. 데이터베이스가 단일 사용자 모드에 있을 필요는 없습니다.The database does not have to be in single-user mode.

다음 Transact-SQLTransact-SQL 문은 READ_COMMITTED_SNAPSHOT을 활성화합니다.The following Transact-SQLTransact-SQL statement enables READ_COMMITTED_SNAPSHOT:

ALTER DATABASE AdventureWorks2016  
    SET READ_COMMITTED_SNAPSHOT ON;  

ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정하면 데이터베이스에서 데이터를 수정한 모든 활성 트랜잭션이 완료될 때까지 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스가 수정된 데이터에 대해 행 버전을 생성하지 않습니다.When the ALLOW_SNAPSHOT_ISOLATION database option is set ON, the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine does not generate row versions for modified data until all active transactions that have modified data in the database complete. 활성 수정 트랜잭션이 있으면 SQL ServerSQL Server에서 이 옵션의 상태를 PENDING_ON로 설정합니다.If there are active modification transactions, SQL ServerSQL Server sets the state of the option to PENDING_ON. 모든 수정 트랜잭션이 완료된 후에는 이 옵션의 상태가 ON으로 변경됩니다.After all of the modification transactions complete, the state of the option is changed to ON. 사용자는 이 옵션이 완전히 ON으로 설정되기 전까지는 해당 데이터베이스에서 스냅샷 트랜잭션을 시작할 수 없습니다.Users cannot start a snapshot transaction in that database until the option is fully ON. 데이터베이스 관리자가 ALLOW_SNAPSHOT_ISOLATION 옵션을 OFF로 설정하면 데이터베이스의 상태가 먼저 PENDING_OFF가 된 후 OFF로 변경됩니다.The database passes through a PENDING_OFF state when the database administrator sets the ALLOW_SNAPSHOT_ISOLATION option to OFF.

다음 Transact-SQLTransact-SQL 문은 ALLOW_SNAPSHOT_ISOLATION을 설정합니다.The following Transact-SQLTransact-SQL statement will enable ALLOW_SNAPSHOT_ISOLATION:

ALTER DATABASE AdventureWorks2016  
    SET ALLOW_SNAPSHOT_ISOLATION ON;  

다음 표에서는 ALLOW_SNAPSHOT_ISOLATION 옵션을 나열하고 각각의 상태에 대해 설명합니다.The following table lists and describes the states of the ALLOW_SNAPSHOT_ISOLATION option. ALTER DATABASE에 ALLOW_SNAPSHOT_ISOLATION 옵션을 사용할 경우 현재 데이터베이스 데이터에 액세스하고 있는 사용자는 차단되지 않습니다.Using ALTER DATABASE with the ALLOW_SNAPSHOT_ISOLATION option does not block users who are currently accessing the database data.

현재 데이터베이스에 대한 스냅샷 격리 프레임워크의 상태State of snapshot isolation framework for current database DescriptionDescription
OFFOFF 스냅샷 격리 트랜잭션에 대한 지원이 활성화되지 않았습니다.The support for snapshot isolation transactions is not activated. 스냅샷 격리 트랜잭션이 허용되지 않습니다.No snapshot isolation transactions are allowed.
PENDING_ONPENDING_ON 스냅샷 격리 트랜잭션에 대한 지원이 OFF에서 ON으로 전환되는 중입니다.The support for snapshot isolation transactions is in transition state (from OFF to ON). 열린 트랜잭션을 완료해야 합니다.Open transactions must complete.

스냅샷 격리 트랜잭션이 허용되지 않습니다.No snapshot isolation transactions are allowed.
켜기ON 스냅샷 격리 트랜잭션에 대한 지원이 활성화되었습니다.The support for snapshot isolation transactions is activated.

스냅샷 트랜잭션이 허용됩니다.Snapshot transactions are allowed.
PENDING_OFFPENDING_OFF 스냅샷 격리 트랜잭션에 대한 지원이 ON에서 OFF로 전환되는 중입니다.The support for snapshot isolation transactions is in transition state (from ON to OFF).

이 시점 이후에 시작된 스냅샷 트랜잭션은 이 데이터베이스에 액세스할 수 없습니다.Snapshot transactions started after this time cannot access this database. 업데이트 트랜잭션은 이 데이터베이스에서 계속해서 버전 관리를 수행합니다.Update transactions still pay the cost of versioning in this database. 기존 스냅샷 트랜잭션은 문제 없이 이 데이터베이스에 액세스할 수 있습니다.Existing snapshot transactions can still access this database without a problem. 데이터베이스 스냅샷 격리 상태가 ON이었을 때 활성화되어 있던 스냅샷 트랜잭션이 모두 완료되어야 PENDING_OFF 상태가 OFF로 변경됩니다.The state PENDING_OFF does not become OFF until all snapshot transactions that were active when the database snapshot isolation state was ON finish.

두 행 버전 관리 데이터베이스 옵션의 상태를 확인하려면 sys.databases 카탈로그 뷰를 사용합니다.Use the sys.databases catalog view to determine the state of both row versioning database options.

모든 사용자 테이블과 master 및 msdb에 저장된 일부 시스템 테이블에 대한 모든 업데이트는 행 버전을 생성합니다.All updates to user tables and some system tables stored in master and msdb generate row versions.

master 및 msdb 데이터베이스에서는 ALLOW_SNAPSHOT_ISOLATION 옵션이 자동으로 ON으로 설정되고 비활성화할 수 없습니다.The ALLOW_SNAPSHOT_ISOLATION option is automatically set ON in the master and msdb databases, and cannot be disabled.

사용자는 master, tempdb 또는 msdb에서 READ_COMMITTED_SNAPSHOT 옵션을 ON으로 설정할 수 없습니다.Users cannot set the READ_COMMITTED_SNAPSHOT option ON in master, tempdb, or msdb.

행 버전 관리 기반 격리 수준 사용Using Row Versioning-based Isolation Levels

행 버전 관리 프레임워크는 항상 SQL ServerSQL Server에 설정되어 있으며 여러 기능에 사용됩니다.The row versioning framework is always enabled in SQL ServerSQL Server, and is used by multiple features. 행 버전 관리 기반 격리 수준을 제공할 뿐만 아니라 MARS(Multiple Active Result Set) 세션과 트리거의 수정 내용을 지원하고 온라인 인덱스 작업을 위한 데이터 읽기를 지원하는 데 사용됩니다.Besides providing row versioning-based isolation levels, it is used to support modifications made in triggers and multiple active result sets (MARS) sessions, and to support data reads for ONLINE index operations.

행 버전 관리 기반 격리 수준은 데이터베이스 수준에서 설정됩니다.Row versioning-based isolation levels are enabled at the database level. 설정된 데이터베이스의 개체에 액세스하는 애플리케이션은 모두 다음과 같은 격리 수준을 사용하여 쿼리를 실행할 수 있습니다.Any application accessing objects from enabled databases can run queries using the following isolation levels:

  • 다음 코드 예제에서는 READ_COMMITTED_SNAPSHOT 데이터베이스 옵션을 ON으로 설정하여 행 버전 관리를 사용하는 커밋된 읽기를 보여 줍니다.Read-committed that uses row versioning by setting the READ_COMMITTED_SNAPSHOT database option to ON as shown in the following code example:

    ALTER DATABASE AdventureWorks2016  
        SET READ_COMMITTED_SNAPSHOT ON;  
    

    데이터베이스에 READ_COMMITTED_SNAPSHOT을 설정하면 커밋된 읽기 격리 수준으로 실행되는 모든 쿼리에 행 버전 관리가 사용됩니다. 즉, 읽기 작업 시 업데이트 작업이 차단되지 않습니다.When the database is enabled for READ_COMMITTED_SNAPSHOT, all queries running under the read committed isolation level use row versioning, which means that read operations do not block update operations.

  • 다음 코드 예에서는 ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정하여 스냅샷 격리를 보여 줍니다.Snapshot isolation by setting the ALLOW_SNAPSHOT_ISOLATION database option to ON as shown in the following code example:

    ALTER DATABASE AdventureWorks2016  
        SET ALLOW_SNAPSHOT_ISOLATION ON;  
    

    스냅샷 격리로 실행되는 트랜잭션은 스냅샷이 설정된 데이터베이스의 테이블에 액세스할 수 있습니다.A transaction running under snapshot isolation can access tables in the database that have been enabled for snapshot. 스냅샷이 설정되지 않은 테이블에 액세스하려면 격리 수준을 변경해야 합니다.To access tables that have not been enabled for snapshot, the isolation level must be changed. 예를 들어 다음 코드 예제에서는 스냅샷 트랜잭션으로 실행되는 동안 두 테이블을 조인하는 SELECT 문을 보여 줍니다.For example, the following code example shows a SELECT statement that joins two tables while running under a snapshot transaction. 한 테이블은 스냅샷 격리가 설정되지 않은 데이터베이스에 속합니다.One table belongs to a database in which snapshot isolation is not enabled. 스냅샷 격리에서 SELECT 문을 실행하면 실행이 실패합니다.When the SELECT statement runs under snapshot isolation, it fails to execute successfully.

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT;  
    BEGIN TRAN  
        SELECT t1.col5, t2.col5  
            FROM Table1 as t1  
            INNER JOIN SecondDB.dbo.Table2 as t2  
                ON t1.col1 = t2.col2;  
    

    다음 코드 예제에서는 트랜잭션 격리 수준을 커밋된 읽기로 변경하도록 수정된 동일한 SELECT 문을 보여 줍니다.The following code example shows the same SELECT statement that has been modified to change the transaction isolation level to read-committed. 이렇게 변경하면 SELECT 문이 성공적으로 실행됩니다.Because of this change, the SELECT statement executes successfully.

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT;  
    BEGIN TRAN  
        SELECT t1.col5, t2.col5  
            FROM Table1 as t1  
            WITH (READCOMMITTED)  
            INNER JOIN SecondDB.dbo.Table2 as t2  
                ON t1.col1 = t2.col2;  
    

행 버전 관리 기반 격리 수준을 사용하는 트랜잭션의 제한 사항Limitations of Transactions Using Row Versioning-based Isolation Levels

행 버전 관리 기반 격리 수준을 사용할 때 다음 제한 사항을 고려하십시오.Consider the following limitations when working with row versioning-based isolation levels:

  • tempdb, msdb 또는 master에는 READ_COMMITTED_SNAPSHOT을 설정할 수 없습니다.READ_COMMITTED_SNAPSHOT cannot be enabled in tempdb, msdb, or master.

  • 전역 임시 테이블은 tempdb에 저장됩니다.Global temp tables are stored in tempdb. 스냅샷 트랜잭션 내의 전역 임시 테이블에 액세스할 때 다음 중 하나를 수행해야 합니다.When accessing global temp tables inside a snapshot transaction, one of the following must happen:

    • tempdb에서 ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정합니다.Set the ALLOW_SNAPSHOT_ISOLATION database option ON in tempdb.
    • 격리 힌트를 사용하여 문에 대한 격리 수준을 변경합니다.Use an isolation hint to change the isolation level for the statement.
  • 다음과 같은 경우 스냅샷 트랜잭션이 실패합니다.Snapshot transactions fail when:

    • 스냅샷 트랜잭션이 시작된 후 데이터베이스에 액세스하기 전에 데이터베이스가 읽기 전용으로 설정됩니다.A database is made read-only after the snapshot transaction starts, but before the snapshot transaction accesses the database.
    • 여러 데이터베이스의 개체에 액세스하는 경우 스냅샷 트랜잭션이 시작된 후 데이터베이스에 액세스하기 전에 데이터베이스 복구를 수반하는 방식으로 데이터베이스 상태가 변경됩니다.If accessing objects from multiple databases, a database state was changed in such a way that database recovery occurred after a snapshot transaction starts, but before the snapshot transaction accesses the database. 예를 들어 데이터베이스가 OFFLINE으로 설정되었다가 ONLINE으로 설정되거나 데이터베이스가 자동으로 닫히고 열리거나 데이터베이스가 분리되고 연결됩니다.For example: the database was set to OFFLINE and then to ONLINE, database autoclose and open, or database detach and attach.
  • 분산 분할된 데이터베이스의 쿼리를 포함하여 분산 트랜잭션은 스냅샷 격리로 지원되지 않습니다.Distributed transactions, including queries in distributed partitioned databases, are not supported under snapshot isolation.

  • SQL ServerSQL Server는 여러 버전의 시스템 메타데이터를 보관하지 않습니다.does not keep multiple versions of system metadata. 테이블의 DDL(데이터 정의 언어) 문이나 기타 데이터베이스 개체(인덱스, 뷰, 데이터 형식, 저장 프로시저 및 공용 언어 런타임 함수)는 메타데이터를 변경합니다.Data definition language (DDL) statements on tables and other database objects (indexes, views, data types, stored procedures, and common language runtime functions) change metadata. DDL 문이 개체를 수정하면 스냅샷 격리의 개체에 대한 동시 참조로 인해 스냅샷 트랜잭션이 실패합니다.If a DDL statement modifies an object, any concurrent reference to the object under snapshot isolation causes the snapshot transaction to fail. READ_COMMITTED_SNAPSHOT 데이터베이스 옵션이 ON이면 커밋된 읽기 트랜잭션에 이러한 제한 사항이 없습니다.Read-committed transactions do not have this limitation when the READ_COMMITTED_SNAPSHOT database option is ON.

    예를 들어 데이터베이스 관리자가 다음 ALTER INDEX 문을 실행합니다.For example, a database administrator executes the following ALTER INDEX statement.

    USE AdventureWorks2016;  
    GO  
    ALTER INDEX AK_Employee_LoginID  
        ON HumanResources.Employee REBUILD;  
    GO  
    

    ALTER INDEX 문이 실행된 후 HumanResources.Employee 테이블을 참조하려고 하면 ALTER INDEX 문 실행 시 활성 상태인 모든 스냅샷 트랜잭션에 오류가 발생합니다.Any snapshot transaction that is active when the ALTER INDEX statement is executed receives an error if it attempts to reference the HumanResources.Employee table after the ALTER INDEX statement is executed. 행 버전 관리를 사용하는 커밋된 읽기 트랜잭션은 영향을 받지 않습니다.Read-committed transactions using row versioning are not affected.

    참고

    BULK INSERT 작업을 수행할 때 대상 테이블 메타데이터가 변경될 수 있습니다. 제약 조건 검사를 해제한 경우를 예로 들 수 있습니다.BULK INSERT operations may cause changes to target table metadata (for example, when disabling constraint checks). 이렇게 대상 테이블 메타데이터가 변경되면 동시 스냅샷 격리 트랜잭션이 대량 삽입된 테이블에 액세스할 수 없습니다.When this happens, concurrent snapshot isolation transactions accessing bulk inserted tables fail.

잠금 및 행 버전 관리 사용자 지정Customizing Locking and Row Versioning

잠금 제한 시간 사용자 지정Customizing the Lock Time-Out

다른 트랜잭션에서 이미 리소스에 대해 충돌되는 잠금을 소유하고 있어 MicrosoftMicrosoft SQL Server 데이터베이스 엔진SQL Server Database Engine의 인스턴스에서 트랜잭션에 잠금을 허가할 수 없는 경우 이 트랜잭션은 기존 잠금이 해제되기를 기다리면서 차단됩니다.When an instance of the MicrosoftMicrosoft SQL Server 데이터베이스 엔진SQL Server Database Engine cannot grant a lock to a transaction because another transaction already owns a conflicting lock on the resource, the first transaction becomes blocked waiting for the existing lock to be released. 기본적으로 정해진 제한 시간은 없으며 리소스를 잠그기 전에 해당 리소스가 잠겨 있는지 여부를 확인할 수 없습니다. 단, 데이터에 대한 액세스를 시도할 수는 있으나 이로 인해 무기한으로 차단될 수 있습니다.By default, there is no mandatory time-out period and no way to test whether a resource is locked before locking it, except to attempt to access the data (and potentially get blocked indefinitely).

참고

SQL ServerSQL Server에서는 sys.dm_os_waiting_tasks 동적 관리 뷰를 사용하여 프로세스가 차단되었는지 여부와 프로세스를 차단하고 있는 주체를 확인할 수 있습니다.In SQL ServerSQL Server, use the sys.dm_os_waiting_tasks dynamic management view to determine whether a process is being blocked and who is blocking it. 이전 버전의 SQL ServerSQL Server에서는 sp_who 시스템 저장 프로시저를 사용합니다.In earlier versions of SQL ServerSQL Server, use the sp_who system stored procedure.

LOCK_TIMEOUT 설정을 사용하여 문이 차단된 리소스를 기다리는 최대 시간을 설정할 수 있습니다.The LOCK_TIMEOUT setting allows an application to set a maximum time that a statement waits on a blocked resource. 문이 LOCK_TIMEOUT 설정보다 오래 기다린 경우 차단된 문은 자동으로 취소되고 오류 메시지 1222(Lock request time-out period exceeded)가 애플리케이션으로 반환됩니다.When a statement has waited longer than the LOCK_TIMEOUT setting, the blocked statement is canceled automatically, and error message 1222 (Lock request time-out period exceeded) is returned to the application. 그러나 문을 포함하는 트랜잭션은 SQL ServerSQL Server에서 롤백되거나 취소되지 않습니다.Any transaction containing the statement, however, is not rolled back or canceled by SQL ServerSQL Server. 따라서 애플리케이션에는 오류 메시지 1222를 트래핑할 수 있는 오류 처리기가 있어야 합니다.Therefore, the application must have an error handler that can trap error message 1222. 애플리케이션에서 오류를 트래핑하지 않으면 트랜잭션 내의 각 문이 취소된 것을 모르고 애플리케이션이 계속 진행하여 나중에 트랜잭션의 문이 실행되지 않은 문을 참조할 경우 오류가 발생할 수 있습니다.If an application does not trap the error, the application can proceed unaware that an individual statement within a transaction has been canceled, and errors can occur because statements later in the transaction might depend on the statement that was never executed.

오류 메시지 1222를 트래핑하는 오류 처리기를 구현하면 애플리케이션에서 시간 초과 상황을 처리하고 차단된 문을 자동으로 다시 전송하거나 전체 트랜잭션을 롤백하는 등의 해결 동작을 취할 수 있습니다.Implementing an error handler that traps error message 1222 allows an application to handle the time-out situation and take remedial action, such as: automatically resubmitting the statement that was blocked or rolling back the entire transaction.

현재 LOCK_TIMEOUT 설정을 확인하려면 @@LOCK_TIMEOUT 함수를 실행합니다.To determine the current LOCK_TIMEOUT setting, execute the @@LOCK_TIMEOUT function:

SELECT @@lock_timeout;  
GO  

트랜잭션 격리 수준 사용자 지정Customizing Transaction Isolation Level

READ COMMITTED는 MicrosoftMicrosoft SQL Server 데이터베이스 엔진SQL Server Database Engine의 기본 격리 수준입니다.READ COMMITTED is the default isolation level for the MicrosoftMicrosoft SQL Server 데이터베이스 엔진SQL Server Database Engine. 애플리케이션을 다른 격리 수준에서 실행해야 하는 경우 다음과 같은 방법으로 격리 수준을 설정할 수 있습니다.If an application must operate at a different isolation level, it can use the following methods to set the isolation level:

  • SET TRANSACTION ISOLATION LEVEL 문을 실행합니다.Run the SET TRANSACTION ISOLATION LEVEL statement.
  • System.Data.SqlClient 관리 네임스페이스를 사용하는 ADO.NET 애플리케이션에서는 SqlConnection.BeginTransaction 메서드를 사용하여 IsolationLevel 옵션을 지정할 수 있습니다.ADO.NET applications that use the System.Data.SqlClient managed namespace can specify an IsolationLevel option by using the SqlConnection.BeginTransaction method.
  • ADO를 사용하는 애플리케이션에서는 Autocommit Isolation Levels 속성을 설정할 수 있습니다.Applications that use ADO can set the Autocommit Isolation Levels property.
  • OLE DB를 사용하는 애플리케이션에서는 트랜잭션을 시작할 때 isoLevel 을 원하는 트랜잭션 격리 수준으로 설정하고 ITransactionLocal::StartTransaction을 호출할 수 있습니다.When starting a transaction, applications using OLE DB can call ITransactionLocal::StartTransaction with isoLevel set to the desired transaction isolation level. 자동 커밋 모드에서 격리 수준을 지정할 때 OLE DB를 사용하는 애플리케이션에서는 DBPROPSET_SESSION 속성인 DBPROP_SESS_AUTOCOMMITISOLEVELS를 원하는 트랜잭션 격리 수준으로 설정할 수 있습니다.When specifying the isolation level in autocommit mode, applications that use OLE DB can set the DBPROPSET_SESSION property DBPROP_SESS_AUTOCOMMITISOLEVELS to the desired transaction isolation level.
  • ODBC를 사용하는 애플리케이션에서는 SQLSetConnectAttr를 사용하여 SQL_COPT_SS_TXN_ISOLATION 특성을 설정할 수 있습니다.Applications that use ODBC can set the SQL_COPT_SS_TXN_ISOLATION attribute by using SQLSetConnectAttr.

격리 수준을 지정하면 SQL ServerSQL Server 세션에서 모든 쿼리와 DML(데이터 조작 언어) 문의 잠금 동작이 해당 격리 수준에서 작동합니다.When the isolation level is specified, the locking behavior for all queries and data manipulation language (DML) statements in the SQL ServerSQL Server session operates at that isolation level. 세션이 종료되거나 격리 수준을 다른 수준으로 설정할 때까지 해당 격리 수준이 적용됩니다.The isolation level remains in effect until the session terminates or until the isolation level is set to another level.

다음 예에서는 SERIALIZABLE 격리 수준을 설정합니다.The following example sets the SERIALIZABLE isolation level:

USE AdventureWorks2016;  
GO  
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;  
GO  
BEGIN TRANSACTION;  
SELECT BusinessEntityID  
    FROM HumanResources.Employee;  
GO  

필요에 따라 테이블 수준 힌트를 지정하여 개별 쿼리나 DML 문에 대해 격리 수준을 무시할 수 있습니다.The isolation level can be overridden for individual query or DML statements, if necessary, by specifying a table-level hint. 테이블 수준 힌트를 지정해도 세션의 다른 문에는 영향을 주지 않습니다.Specifying a table-level hint does not affect other statements in the session. 꼭 필요한 경우에만 테이블 수준 힌트를 사용하여 기본 동작을 변경하는 것이 좋습니다.We recommend that table-level hints be used to change the default behavior only when absolutely necessary.

데이터를 읽을 때 공유 잠금을 요청하지 않는 수준으로 격리 수준이 설정된 경우에도 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 잠금을 획득해야 할 수 있습니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine might have to acquire locks when reading metadata even when the isolation level is set to a level where share locks are not requested when reading data. 예를 들어 커밋되지 않은 읽기 격리 수준에서 실행되는 트랜잭션은 데이터를 읽을 때 공유 잠금을 획득하지 않지만 시스템 카탈로그 뷰를 읽을 때 잠금을 요청하는 경우도 있습니다.For example, a transaction running at the read-uncommitted isolation level does not acquire share locks when reading data, but might sometime request locks when reading a system catalog view. 즉 동시 트랜잭션이 해당 테이블의 메타데이터를 수정할 때 커밋되지 않은 읽기 트랜잭션이 테이블 쿼리를 차단할 수 있습니다.This means it is possible for a read uncommitted transaction to cause blocking when querying a table when a concurrent transaction is modifying the metadata of that table.

현재 설정된 트랜잭션 격리 수준을 확인하려면 다음 예와 같이 DBCC USEROPTIONS 문을 사용합니다.To determine the transaction isolation level currently set, use the DBCC USEROPTIONS statement as shown in the following example. 이 결과 집합은 사용 중인 컴퓨터의 결과 집합과 다를 수 있습니다.The result set may vary from the result set on your system.

USE AdventureWorks2016;  
GO  
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;  
GO  
DBCC USEROPTIONS;  
GO  

결과 집합은 다음과 같습니다.Here is the result set.

Set Option                   Value  
---------------------------- -------------------------------------------  
textsize                     2147483647  
language                     us_english  
dateformat                   mdy  
datefirst                    7  
...                          ...  
Isolation level              repeatable read  
 
(14 row(s) affected)   
 
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

잠금 힌트Locking Hints

SELECT, INSERT, UPDATE 및 DELETE 문의 개별 테이블 참조에 대해 잠금 힌트를 지정할 수 있습니다.Locking hints can be specified for individual table references in the SELECT, INSERT, UPDATE, and DELETE statements. 힌트는 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스가 테이블 데이터에 대해 사용하는 잠금 유형 또는 행 버전 관리를 지정합니다.The hints specify the type of locking or row versioning the instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine uses for the table data. 테이블 수준의 잠금 힌트는 개체에 대해 얻은 잠금 유형에 대해 더 세부적인 제어가 필요할 때 사용할 수 있습니다.Table-level locking hints can be used when a finer control of the types of locks acquired on an object is required. 이러한 잠금 힌트는 세션에 대해 현재 트랜잭션 격리 수준을 무시합니다.These locking hints override the current transaction isolation level for the session.

특정 잠금 힌트와 해당 동작에 대한 자세한 내용은 Table Hints(Transact-SQL)를 참조하십시오.For more information about the specific locking hints and their behaviors, see Table Hints (Transact-SQL).

참고

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 거의 항상 올바른 잠금 수준을 선택합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine almost always chooses the correct locking level. 필요할 때만 테이블 수준의 잠금 힌트를 사용하여 기본 잠금 동작을 변경하는 것이 좋습니다.We recommend that table-level locking hints be used to change the default locking behavior only when necessary. 잠금 수준의 허용을 취소하면 동시성에 영향을 줄 수 있습니다.Disallowing a locking level can adversely affect concurrency.

데이터를 읽을 때 공유 잠금 요청을 막는 잠금 힌트를 사용하여 SELECT를 처리하는 경우에도 메타데이터를 읽을 때 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 잠금을 획득해야 할 수 있습니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine might have to acquire locks when reading metadata, even when processing a select with a locking hint that prevents requests for share locks when reading data. 예를 들어 NOLOCK 힌트를 사용하는 SELECT는 데이터를 읽을 때 공유 잠금을 획득하지 않지만 시스템 카탈로그 뷰를 읽을 때는 경우에 따라 잠금을 요청할 수 있습니다.For example, a SELECT using the NOLOCK hint does not acquire share locks when reading data, but might sometime request locks when reading a system catalog view. 즉, NOLOCK를 사용하는 SELECT 문을 차단할 수 있습니다.This means it is possible for a SELECT statement using NOLOCK to be blocked.

다음 예와 같이 트랜잭션 격리 수준이 SERIALIZABLE로 설정되고 테이블 수준 잠금 힌트인 NOLOCKSELECT 문과 함께 사용되면 일반적으로 직렬화 가능 트랜잭션을 유지 관리하는 데 사용되는 키 범위 잠금이 적용되지 않습니다.As shown in the following example, if the transaction isolation level is set to SERIALIZABLE, and the table-level locking hint NOLOCK is used with the SELECT statement, key-range locks typically used to maintain serializable transactions are not taken.

USE AdventureWorks2016;  
GO  
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;  
GO  
BEGIN TRANSACTION;  
GO  
SELECT JobTitle  
    FROM HumanResources.Employee WITH (NOLOCK);  
GO  
  
-- Get information about the locks held by   
-- the transaction.  
SELECT    
        resource_type,   
        resource_subtype,   
        request_mode  
    FROM sys.dm_tran_locks  
    WHERE request_session_id = @@spid;  
  
-- End the transaction.  
ROLLBACK;  
GO  

HumanResources.Employee를 참조하는 유일한 잠금은 스키마 안정성(Sch-S) 잠금입니다.The only lock taken that references HumanResources.Employee is a schema stability (Sch-S) lock. 이 경우 순차성은 더 이상 보장되지 않습니다.In this case, serializability is no longer guaranteed.

SQL Server 2019 (15.x)SQL Server 2019 (15.x)에서는 ALTER TABLELOCK_ESCALATION 옵션에서 테이블 잠금을 선호하지 않을 수 있으며 분할된 테이블에 HoBT 잠금을 설정할 수 있습니다.In SQL Server 2019 (15.x)SQL Server 2019 (15.x), the LOCK_ESCALATION option of ALTER TABLE can disfavor table locks, and enable HoBT locks on partitioned tables. 이 옵션은 잠금 힌트가 아니지만 잠금 에스컬레이션을 줄이는 데 사용할 수 있습니다.This option is not a locking hint, but can be used to reduce lock escalation. 자세한 내용은 ALTER TABLE(Transact-SQL)을 참조하세요.For more information, see ALTER TABLE (Transact-SQL).

인덱스 잠금 사용자 지정Customizing Locking for an Index

SQL Server 데이터베이스 엔진SQL Server Database Engine은 대부분의 경우 쿼리에 가장 적합한 잠금 세분성을 자동으로 선택하는 동적 잠금 전략을 사용합니다.The SQL Server 데이터베이스 엔진SQL Server Database Engine uses a dynamic locking strategy that automatically chooses the best locking granularity for queries in most cases. 페이지 잠금 및 행 잠금이 설정되어 있는 기본 잠금 수준은 잘 알려져 있으며 일관적인 테이블 또는 인덱스 액세스 패턴이 아닌 경우 및 리소스 충돌 문제를 해결해야 하는 경우 재정의하지 않는 것이 좋습니다.We recommend that you do not override the default locking levels, which have page and row locking on, unless table or index access patterns are well understood and consistent, and there is a resource contention problem to solve. 잠금 수준을 재정의하면 테이블 또는 인덱스에 대한 동시 액세스에 심각한 방해가 될 수 있습니다.Overriding a locking level can significantly impede concurrent access to a table or index. 예를 들어 사용자의 액세스가 빈번한 대규모 테이블에 테이블 수준 잠금만을 지정하는 경우, 사용자가 테이블에 액세스하려면 테이블 수준 잠금이 해제될 때까지 기다려야 하므로 병목 현상이 발생할 수 있습니다.For example, specifying only table-level locks on a large table that users access heavily can cause bottlenecks because users must wait for the table-level lock to be released before accessing the table.

잘 알려져 있으며 일관된 액세스 패턴의 경우 페이지 잠금 또는 행 잠금을 허용하지 않는 것이 좋은 경우가 있습니다.There are a few cases where disallowing page or row locking can be beneficial, if the access patterns are well understood and consistent. 예를 들어 데이터베이스 애플리케이션에서 일괄 처리를 통해 매주 업데이트되는 조회 테이블을 사용하는 경우를 가정합니다.For example, a database application uses a lookup table that is updated weekly in a batch process. 동시 판독기는 공유(S) 잠금으로 테이블에 액세스하고, 주간 일괄 업데이트는 배타적(X) 잠금으로 테이블에 액세스합니다.Concurrent readers access the table with a shared (S) lock and the weekly batch update accesses the table with an exclusive (X) lock. 테이블에서 페이지 및 행 잠금을 해제하면 판독기가 공유 테이블 잠금을 통해 동시에 테이블에 액세스할 수 있어 주중 잠금 오버헤드가 줄어듭니다.Turning off page and row locking on the table reduces the locking overhead throughout the week by allowing readers to concurrently access the table through shared table locks. 일괄 작업을 실행하면 배타적 테이블 잠금을 얻어 업데이트를 효율적으로 완료할 수 있습니다.When the batch job runs, it can complete the update efficiently because it obtains an exclusive table lock.

주간 일괄 업데이트는 업데이트 실행 동안 동시 판독기의 테이블 액세스를 차단하므로 페이지 및 행 잠금 해제가 허용될 수도, 그렇지 않을 수도 있습니다.Turning off page and row locking might or might not be acceptable because the weekly batch update will block the concurrent readers from accessing the table while the update runs. 행 또는 페이지만 변경하는 일괄 작업의 경우, 행 또는 페이지 수준 잠금을 허용하도록 잠금 수준을 변경하여 다른 세션에서 차단 없이 테이블에서 읽기를 수행하도록 허용할 수 있습니다.If the batch job only changes a few rows or pages, you can change the locking level to allow row or page level locking, which will enable other sessions to read from the table without blocking. 업데이트가 다수 포함된 일괄 작업의 경우, 테이블에 대한 배타적 잠금이 효율적인 일괄 작업 완수를 위한 최상의 방법일 수 있습니다.If the batch job has a large number of updates, obtaining an exclusive lock on the table may be the best way to ensure the batch job finishes efficiently.

2건의 동시 작업에서 모두 페이지 잠금이 필요하여 동일 테이블에서 행 잠금을 구한 다음 차단함에 따라 교착 상태가 발생하는 경우가 있습니다.Occasionally a deadlock occurs when two concurrent operations acquire row locks on the same table and then block because they both need to lock the page. 행 잠금을 허용하지 않으면 두 작업 중 하나를 대기시켜 교착 상태를 방지합니다.Disallowing row locks forces one of the operations to wait, avoiding the deadlock.

인덱스에 사용되는 잠금의 세분성은 CREATE INDEXALTER INDEX 문을 사용하여 설정할 수 있습니다.The granularity of locking used on an index can be set using the CREATE INDEX and ALTER INDEX statements. 잠금 설정은 인덱스 페이지와 테이블 페이지에 모두 적용됩니다.The lock settings apply to both the index pages and the table pages. 또한 CREATE TABLEALTER TABLE 문을 사용하여 PRIMARY KEYUNIQUE 제약 조건에 대한 잠금 세분성을 설정할 수 있습니다.In addition, the CREATE TABLE and ALTER TABLE statements can be used to set locking granularity on PRIMARY KEY and UNIQUE constraints. 이전 버전과의 호환성을 위해 sp_indexoption 시스템 저장 프로시저에서도 세분성을 설정할 수 있습니다.For backwards compatibility, the sp_indexoption system stored procedure can also set the granularity. 특정 인덱스에 대한 현재 잠금 옵션을 표시하려면 INDEXPROPERTY 함수를 사용합니다.To display the current locking option for a given index, use the INDEXPROPERTY function. 페이지 수준 잠금, 행 수준 잠금 또는 페이지 수준 및 행 수준 잠금의 혼합 방법은 인덱스에 따라 허용되지 않을 수 있습니다.Page-level locks, row-level locks, or a combination of page-level and row-level locks can be disallowed for a given index.

허용되지 않는 잠금Disallowed locks 허용되는 잠금Index accessed by
페이지 수준Page level 행 수준 및 테이블 수준 잠금Row-level and table-level locks
행 수준Row level 페이지 수준 및 테이블 수준 잠금Page-level and table-level locks
페이지 수준 및 행 수준Page level and row level 테이블 수준 잠금Table-level locks

고급 트랜잭션 정보Advanced Transaction Information

중첩 트랜잭션Nesting Transactions

명시적 트랜잭션은 중첩할 수 있습니다.Explicit transactions can be nested. 중첩 트랜잭션은 주로 트랜잭션의 기존 프로세스나 활성 트랜잭션이 없는 프로세스에서 호출할 수 있는 저장 프로시저의 트랜잭션을 지원하기 위한 것입니다.This is primarily intended to support transactions in stored procedures that can be called either from a process already in a transaction or from processes that have no active transaction.

다음 예에서는 중첩된 트랜잭션의 용도를 보여 줍니다.The following example shows the intended use of nested transactions. TransProc 프로시저는 프로시저를 실행하는 프로세스의 트랜잭션 모드에 관계없이 트랜잭션을 강제 실행합니다.The procedure TransProc enforces its transaction regardless of the transaction mode of any process that executes it. 트랜잭션이 활성 중일 때 TransProc 을 호출하면 TransProc 에서 중첩된 트랜잭션이 대부분 무시되고 바깥쪽 트랜잭션에서 수행된 최종 동작을 기준으로 INSERT 문이 커밋 또는 롤백됩니다.If TransProc is called when a transaction is active, the nested transaction in TransProc is largely ignored, and its INSERT statements are committed or rolled back based on the final action taken for the outer transaction. 처리 중인 트랜잭션이 없는 프로세스에서 TransProc를 실행하면 실제로 프로시저 마지막에서 COMMIT TRANSACTIONINSERT 문이 커밋됩니다.If TransProc is executed by a process that does not have an outstanding transaction, the COMMIT TRANSACTION at the end of the procedure effectively commits the INSERT statements.

SET QUOTED_IDENTIFIER OFF;  
GO  
SET NOCOUNT OFF;  
GO  
CREATE TABLE TestTrans(Cola INT PRIMARY KEY,  
               Colb CHAR(3) NOT NULL);  
GO  
CREATE PROCEDURE TransProc @PriKey INT, @CharCol CHAR(3) AS  
BEGIN TRANSACTION InProc  
INSERT INTO TestTrans VALUES (@PriKey, @CharCol)  
INSERT INTO TestTrans VALUES (@PriKey + 1, @CharCol)  
COMMIT TRANSACTION InProc;  
GO  
/* Start a transaction and execute TransProc. */  
BEGIN TRANSACTION OutOfProc;  
GO  
EXEC TransProc 1, 'aaa';  
GO  
/* Roll back the outer transaction, this will  
   roll back TransProc's nested transaction. */  
ROLLBACK TRANSACTION OutOfProc;  
GO  
EXECUTE TransProc 3,'bbb';  
GO  
/* The following SELECT statement shows only rows 3 and 4 are   
   still in the table. This indicates that the commit  
   of the inner transaction from the first EXECUTE statement of  
   TransProc was overridden by the subsequent rollback. */  
SELECT * FROM TestTrans;  
GO  

안쪽 트랜잭션 커밋은 SQL Server 데이터베이스 엔진SQL Server Database Engine에서 무시합니다.Committing inner transactions is ignored by the SQL Server 데이터베이스 엔진SQL Server Database Engine. 트랜잭션은 가장 바깥쪽 트랜잭션 마지막에 수행된 동작을 기준으로 커밋 또는 롤백됩니다.The transaction is either committed or rolled back based on the action taken at the end of the outermost transaction. 바깥쪽 트랜잭션이 커밋되면 안쪽 중첩 트랜잭션도 커밋됩니다.If the outer transaction is committed, the inner nested transactions are also committed. 바깥쪽 트랜잭션이 롤백되면 안쪽 트랜잭션이 개별적으로 커밋되었는지에 관계없이 모든 안쪽 트랜잭션이 롤백됩니다.If the outer transaction is rolled back, then all inner transactions are also rolled back, regardless of whether or not the inner transactions were individually committed.

COMMIT TRANSACTION 또는 COMMIT WORK에 대한 각 호출은 마지막으로 실행된 BEGIN TRANSACTION에 적용됩니다.Each call to COMMIT TRANSACTION or COMMIT WORK applies to the last executed BEGIN TRANSACTION. BEGIN TRANSACTION 문을 중첩하면 COMMIT 문이 마지막으로 중첩된 트랜잭션, 즉 가장 안쪽의 트랜잭션에만 적용됩니다.If the BEGIN TRANSACTION statements are nested, then a COMMIT statement applies only to the last nested transaction, which is the innermost transaction. 중첩된 트랜잭션 내의 COMMIT TRANSACTION transaction_name 문이 바깥쪽 트랜잭션의 트랜잭션 이름을 참조해도 커밋은 가장 안쪽의 트랜잭션에만 적용됩니다.Even if a COMMIT TRANSACTION transaction_name statement within a nested transaction refers to the transaction name of the outer transaction, the commit applies only to the innermost transaction.

ROLLBACK TRANSACTION 문의 transaction_name 매개 변수는 명명된 중첩 트랜잭션 집합의 안쪽 트랜잭션을 참조할 수 없습니다.It is not legal for the transaction_name parameter of a ROLLBACK TRANSACTION statement to refer to the inner transactions of a set of named nested transactions. transaction_name 은 가장 바깥쪽 트랜잭션의 트랜잭션 이름만 참조할 수 있습니다.transaction_name can refer only to the transaction name of the outermost transaction. 바깥쪽 트랜잭션의 이름을 사용하는 ROLLBACK TRANSACTION transaction_name 문이 중첩 트랜잭션 집합의 특정 수준에서 실행되면 중첩된 트랜잭션이 모두 롤백됩니다.If a ROLLBACK TRANSACTION transaction_name statement using the name of the outer transaction is executed at any level of a set of nested transactions, all of the nested transactions are rolled back. ROLLBACK WORK 또는 ROLLBACK TRANSACTION 문이 transaction_name 매개 변수 없이 중첩 트랜잭션 집합의 특정 수준에서 실행되면 가장 바깥쪽 트랜잭션을 포함하여 모든 중첩 트랜잭션이 롤백됩니다.If a ROLLBACK WORK or ROLLBACK TRANSACTION statement without a transaction_name parameter is executed at any level of a set of nested transaction, it rolls back all of the nested transactions, including the outermost transaction.

@@TRANCOUNT 함수는 현재 트랜잭션 중첩 수준을 기록합니다.The @@TRANCOUNT function records the current transaction nesting level. BEGIN TRANSACTION 문은 @@TRANCOUNT를 1씩 증가시킵니다.Each BEGIN TRANSACTION statement increments @@TRANCOUNT by one. COMMIT TRANSACTION 또는 COMMIT WORK 문은 각기 @@TRANCOUNT을 1씩 감소시킵니다.Each COMMIT TRANSACTION or COMMIT WORK statement decrements @@TRANCOUNT by one. 트랜잭션 이름이 없는 ROLLBACK WORK 또는 ROLLBACK TRANSACTION 문은 모든 중첩 트랜잭션을 롤백하고 @@TRANCOUNT을 0으로 되돌립니다.A ROLLBACK WORK or a ROLLBACK TRANSACTION statement that does not have a transaction name rolls back all nested transactions and decrements @@TRANCOUNT to 0. 중첩 트랜잭션 집합에서 가장 바깥쪽 트랜잭션의 트랜잭션 이름을 사용하는 ROLLBACK TRANSACTION은 모든 중첩 트랜잭션을 롤백하고 @@TRANCOUNT를 0으로 되돌립니다.A ROLLBACK TRANSACTION that uses the transaction name of the outermost transaction in a set of nested transactions rolls back all of the nested transactions and decrements @@TRANCOUNT to 0. 트랜잭션 안에 있는지 확실하지 않을 때는 SELECT @@TRANCOUNT을 조회하여 1 이상인지 확인합니다.When you are unsure if you are already in a transaction, SELECT @@TRANCOUNT to determine if it is 1 or more. @@TRANCOUNT이 0이면 트랜잭션 밖에 있는 것입니다.If @@TRANCOUNT is 0, you are not in a transaction.

바운드 세션 사용Using Bound Sessions

바운드 세션을 통해 같은 서버의 여러 세션 간에 동작을 편리하게 조정할 수 있습니다.Bound sessions ease the coordination of actions across multiple sessions on the same server. 바운드 세션을 사용하면 두 개 이상의 세션에서 같은 트랜잭션과 잠금을 공유할 수 있으며 여러 바운드 세션이 잠금 충돌 없이 같은 데이터 작업을 수행할 수 있습니다.Bound sessions allow two or more sessions to share the same transaction and locks, and can work on the same data without lock conflicts. 바운드 세션은 같은 애플리케이션 내의 여러 세션에서 생성되거나 개별 세션의 여러 애플리케이션에서 생성될 수 있습니다.Bound sessions can be created from multiple sessions within the same application or from multiple applications with separate sessions.

바운드 세션에 참여하려면 세션에서 개방형 Data Services를 통한 sp_getbindtoken 또는 srv_getbindtoken를 호출하여 바인드 토큰을 가져와야 합니다.To participate in a bound session, a session calls sp_getbindtoken or srv_getbindtoken (through Open Data Services) to get a bind token. 바인드 토큰은 각 바운드 트랜잭션을 고유하게 식별하는 문자열입니다.A bind token is a character string that uniquely identifies each bound transaction. 가져온 바인드 토큰은 현재 세션과 바인딩할 다른 세션으로 전송됩니다.The bind token is then sent to the other sessions to be bound with the current session. 다른 세션은 첫 번째 세션으로부터 받은 바인드 토큰으로 sp_bindsession 을 호출하여 트랜잭션에 바인딩합니다.The other sessions bind to the transaction by calling sp_bindsession, using the bind token received from the first session.

참고

sp_getbindtoken 또는 srv_getbindtoken가 성공하려면 세션에 활성 사용자 트랜잭션이 있어야 합니다.A session must have an active user transaction in order for sp_getbindtoken or srv_getbindtoken to succeed.

애플리케이션 코드에 대한 첫 번째 세션을 만들고 애플리케이션 코드의 세션을 첫 번째 세션에 바인딩하는 애플리케이션 코드에서 바인드 토큰을 전송해야 합니다.Bind tokens must be transmitted from the application code that makes the first session to the application code that subsequently binds their sessions to the first session. 애플리케이션이 다른 프로세스에서 시작한 트랜잭션에 대한 바인드 토큰을 얻을 수 있는 Transact-SQLTransact-SQL 문이나 API 함수는 없습니다.There is no Transact-SQLTransact-SQL statement or API function that an application can use to get the bind token for a transaction started by another process. 다음과 같은 방법으로 바인드 토큰을 전송할 수 있습니다.Some of the methods that can be used to transmit a bind token include the following:

  • 세션이 모두 같은 애플리케이션 프로세스에서 시작되는 경우에는 바인드 토큰을 글로벌 메모리에 저장하거나 매개 변수로 함수에 전달할 수 있습니다.If the sessions are all initiated from the same application process, bind tokens can be stored in global memory or passed into functions as a parameter.

  • 세션이 개별 애플리케이션 프로세스에서 생성되는 경우에는 RPC(원격 프로시저 호출)나 DDE(동적 데이터 교환) 등의 IPC(프로세스 간 통신)를 사용하여 바인드 토큰을 전송할 수 있습니다.If the sessions are made from separate application processes, bind tokens can be transmitted using interprocess communication (IPC), such as a remote procedure call (RPC) or dynamic data exchange (DDE).

  • 첫 번째 세션에 바인딩하려는 세션에서 읽을 수 있는 SQL Server 데이터베이스 엔진SQL Server Database Engine 인스턴스의 테이블에 바인드 토큰을 저장할 수 있습니다.Bind tokens can be stored in a table in an instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine that can be read by processes wanting to bind to the first session.

항상 바운드 세션 집합의 한 세션만 활성화될 수 있습니다.Only one session in a set of bound sessions can be active at any time. 세션이 인스턴스에서 문을 실행하고 있거나 인스턴스로부터 보류 중인 결과를 받으면 이 세션에 연결된 다른 세션은 현재 세션이 처리를 마치거나 현재 문을 취소할 때까지 해당 인스턴스에 액세스할 수 없습니다.If one session is executing a statement on the instance or has results pending from the instance, no other session bound to it can access the instance until the current session finishes processing or cancels the current statement. 인스턴스가 다른 바운드 세션의 문을 처리하고 있으면 트랜잭션 공간이 사용 중이므로 나중에 세션을 다시 시도해야 함을 나타내는 오류가 발생합니다.If the instance is busy processing a statement from another of the bound sessions, an error occurs indicating that the transaction space is in use and the session should retry later.

세션을 바인딩할 때 각 세션의 해당 격리 수준 설정이 유지됩니다.When you bind sessions, each session retains its isolation level setting. SET TRANSACTION ISOLATION LEVEL을 사용하여 한 세션의 격리 수준 설정을 변경해도 이 세션에 바인딩된 다른 세션의 설정에는 영향을 주지 않습니다.Using SET TRANSACTION ISOLATION LEVEL to change the isolation level setting of one session does not affect the setting of any other session bound to it.

바운드 세션 유형Types of Bound Sessions

바운드 세션에는 로컬과 분산의 두 가지 유형이 있습니다.The two types of bound sessions are local and distributed.

  • 로컬 바운드 세션Local bound session
    여러 바운드 세션이 SQL Server 데이터베이스 엔진SQL Server Database Engine의 단일 인스턴스에서 단일 트랜잭션의 트랜잭션 공간을 공유할 수 있습니다.Allows bound sessions to share the transaction space of a single transaction in a single instance of the SQL Server 데이터베이스 엔진SQL Server Database Engine.

  • 분산 바운드 세션Distributed bound session
    MS DTC(MicrosoftMicrosoft Distributed Transaction Coordinator)를 사용하여 전체 트랜잭션을 커밋하거나 롤백할 때까지 여러 바운드 세션이 둘 이상의 인스턴스에서 같은 트랜잭션을 공유할 수 있습니다.Allows bound sessions to share the same transaction across two or more instances until the entire transaction is either committed or rolled back by using MicrosoftMicrosoft Distributed Transaction Coordinator (MS DTC).

분산 바운드 세션은 문자열 바인드 토큰으로 식별되지 않고 분산 트랜잭션 식별 번호로 식별됩니다.Distributed bound sessions are not identified by a character string bind token; they are identified by distributed transaction identification numbers. 바운드 세션이 로컬 트랜잭션과 관련되어 있고 원격 서버에서 SET REMOTE_PROC_TRANSACTIONS ON을 ON으로 설정하여 RPC를 실행하는 경우에는 MS DTC에 의해 로컬 바운드 트랜잭션이 분산 바운드 트랜잭션으로 자동 승격되고 MS DTC 세션이 시작됩니다.If a bound session is involved in a local transaction and executes an RPC on a remote server with SET REMOTE_PROC_TRANSACTIONS ON, the local bound transaction is automatically promoted to a distributed bound transaction by MS DTC and an MS DTC session is started.

바운드 세션 사용 시기When to use Bound Sessions

이전 버전의 SQL ServerSQL Server에서 바운드 세션은 Transact-SQLTransact-SQL 문을 호출하는 프로세스를 대신하여 이 문을 실행해야 하는 확장 저장 프로시저를 개발하는 데 주로 사용되었습니다.In earlier versions of SQL ServerSQL Server, bound sessions were primarily used in developing extended stored procedures that must execute Transact-SQLTransact-SQL statements on behalf of the process that calls them. 호출 프로세스에서 바인드 토큰을 확장 저장 프로시저의 한 매개 변수로 전달하도록 설정하면 프로시저가 호출 프로세스의 트랜잭션 공간에 참여하여 호출 프로시저와 확장 저장 프로시저가 통합됩니다.Having the calling process pass in a bind token as one parameter of the extended stored procedure allows the procedure to join the transaction space of the calling process, thereby integrating the extended stored procedure with the calling process.

SQL Server 데이터베이스 엔진SQL Server Database Engine에서는 저장 프로시저를 CLR로 작성하여 확장 저장 프로시저보다 뛰어난 안전성, 확장성 및 안정성을 제공합니다.In the SQL Server 데이터베이스 엔진SQL Server Database Engine, stored procedures written using CLR are more secure, scalable, and stable than extended stored procedures. CLR 저장 프로시저는 SqlContext 개체를 사용하여 sp_bindsession이 아닌 호출 세션의 컨텍스트에 참여합니다.CLR-stored procedures use the SqlContext object to join the context of the calling session, not sp_bindsession.

바운드 세션을 사용하여 단일 업무 트랜잭션에서 함께 작업하는 여러 개별 프로그램에 비즈니스 논리가 통합되는 3계층 애플리케이션을 개발할 수 있습니다.Bound sessions can be used to develop three-tier applications in which business logic is incorporated into separate programs that work cooperatively on a single business transaction. 이러한 프로그램의 경우 데이터베이스 액세스를 잘 조정하도록 코드를 작성해야 합니다.These programs must be coded to carefully coordinate their access to a database. 두 세션이 같은 잠금을 공유하기 때문에 두 프로그램이 동시에 같은 데이터를 수정할 수 없습니다.Because the two sessions share the same locks, the two programs must not try to modify the same data at the same time. 항상 한 세션만 트랜잭션의 일부로 작업을 수행할 수 있으므로 병렬 실행은 불가능합니다.At any point in time, only one session can be doing work as part of the transaction; there can be no parallel execution. 모든 DML 문이 완료되어 결과가 검색된 경우와 같이 잘 정의된 양보점(yield point)에서만 세션 간에 트랜잭션이 전환될 수 있습니다.The transaction can only be switched between sessions at well-defined yield points, such as when all DML statements have completed and their results have been retrieved.

효율적인 트랜잭션 코딩Coding efficient transactions

트랜잭션을 되도록 짧게 유지하는 것이 중요합니다.It is important to keep transactions as short as possible. 트랜잭션이 시작되면 DBMS(데이터베이스 관리 시스템)가 트랜잭션이 끝날 때까지 많은 리소스를 보유하여 트랜잭션의 ACID(원자성, 일관성, 격리성, 영속성) 속성을 보호합니다.When a transaction is started, a database management system (DBMS) must hold many resources until the end of the transaction to protect the atomicity, consistency, isolation, and durability (ACID) properties of the transaction. 데이터가 수정되면 다른 트랜잭션이 읽을 수 없도록 수정된 행이 배타적 잠금으로 보호되어야 하며 트랜잭션이 커밋되거나 롤백될 때까지 배타적 잠금이 유지되어야 합니다.If data is modified, the modified rows must be protected with exclusive locks that prevent any other transaction from reading the rows, and exclusive locks must be held until the transaction is committed or rolled back. 트랜잭션 격리 수준 설정에 따라 SELECT 문에서 트랜잭션이 커밋 또는 롤백될 때까지 보유해야 하는 잠금을 획득할 수 있습니다.Depending on transaction isolation level settings, SELECT statements may acquire locks that must be held until the transaction is committed or rolled back. 특히 많은 사용자가 사용하는 시스템에서는 트랜잭션을 되도록 짧게 유지하여 동시 연결 간에 리소스에 대한 잠금 경합을 줄여야 합니다.Especially in systems with many users, transactions must be kept as short as possible to reduce locking contention for resources between concurrent connections. 실행 시간이 긴 비효율적인 트랜잭션은 사용자 수가 적을 때는 별로 문제가 되지 않지만 사용자가 많을 때는 심각한 문제가 됩니다.Long-running, inefficient transactions may not be a problem with small numbers of users, but they are intolerable in a system with thousands of users. SQL Server 2014(12.x)SQL Server 2014 (12.x)SQL ServerSQL Server부터 지연된 영구 트랜잭션이 지원됩니다.Beginning with SQL Server 2014(12.x)SQL Server 2014 (12.x)SQL ServerSQL Server supports delayed durable transactions. 지연된 내구성 있는 트랜잭션은 내구성을 보장하지 않습니다.Delayed durable transactions do not guarantee durability. 자세한 내용은 트랜잭션 내구성 항목을 참조하세요.See the topic Transaction Durability for more information.

코딩 지침Coding Guidelines

효율적인 트랜잭션을 코딩하려면 다음 지침을 참조하십시오.These are guidelines for coding efficient transactions:

  • 트랜잭션 중 사용자로부터 입력을 요청하지 마십시오.Do not require input from users during a transaction.
    트랜잭션이 시작되기 전에 사용자로부터 필요한 입력 내용을 모두 입력받아야 합니다.Get all required input from users before a transaction is started. 트랜잭션 중 추가 사용자 입력이 필요하면 현재 트랜잭션을 롤백하고 사용자 입력이 제공된 후 트랜잭션을 다시 시작해야 합니다.If additional user input is required during a transaction, roll back the current transaction and restart the transaction after the user input is supplied. 사용자가 즉시 응답하더라도 사람의 반응 속도는 컴퓨터 속도보다 매우 느립니다.Even if users respond immediately, human reaction times are vastly slower than computer speeds. 트랜잭션에 의해 보유된 모든 리소스는 꽤 긴 시간 동안 보유되므로 차단 문제가 발생할 수 있습니다.All resources held by the transaction are held for an extremely long time, which has the potential to cause blocking problems. 사용자가 응답하지 않으면 응답할 때까지 몇 분 또는 몇 시간 동안 트랜잭션이 계속 활성 상태로 남아 있고 중요한 리소스가 잠겨 있게 됩니다.If users do not respond, the transaction remains active, locking critical resources until they respond, which may not happen for several minutes or even hours.

  • 가능하면 데이터를 찾아보는 동안에는 트랜잭션을 열지 마십시오.Do not open a transaction while browsing through data, if at all possible.
    모든 예비 데이터 분석이 완료될 때까지 트랜잭션을 시작하지 말아야 합니다.Transactions should not be started until all preliminary data analysis has been completed.

  • 트랜잭션을 되도록 짧게 유지합니다.Keep the transaction as short as possible.
    수정해야 한다고 판단되면 트랜잭션을 시작하고 수정 문을 실행한 다음 즉시 커밋 또는 롤백합니다.After you know the modifications that have to be made, start a transaction, execute the modification statements, and then immediately commit or roll back. 필요할 때까지는 트랜잭션을 열지 마십시오.Do not open the transaction before it is required.

  • 차단을 줄이려면 읽기 전용 쿼리에 행 버전 관리 기반의 격리 수준을 사용합니다.To reduce blocking, consider using a row versioning-based isolation level for read-only queries.

  • 낮은 트랜잭션 격리 수준을 효율적으로 사용하십시오.Make intelligent use of lower transaction isolation levels.
    대부분의 애플리케이션은 커밋된 읽기 트랜잭션 격리 수준을 사용하도록 코딩할 수 있습니다.Many applications can be readily coded to use a read-committed transaction isolation level. 모든 트랜잭션에서 직렬화 가능 트랜잭션 격리 수준이 필요한 것은 아닙니다.Not all transactions require the serializable transaction isolation level.

  • 낙관적 동시성 옵션과 같이 낮은 커서 동시성 옵션을 효율적으로 사용합니다.Make intelligent use of lower cursor concurrency options, such as optimistic concurrency options.
    동시 업데이트 가능성이 적은 시스템에서는 한 사용자가 데이터를 읽은 후 다른 사용자가 해당 데이터를 변경하여 발생하는 오류를 처리하는 오버헤드가 데이터를 읽을 때마다 행을 잠그는 오버헤드보다 훨씬 적을 수 있습니다.In a system with a low probability of concurrent updates, the overhead of dealing with an occasional "somebody else changed your data after you read it" error can be much lower than the overhead of always locking rows as they are read.

  • 트랜잭션에서는 가능한 적은 양의 데이터에 액세스합니다.Access the least amount of data possible while in a transaction.
    이렇게 하면 잠긴 행 수가 줄어들어 트랜잭션 간의 경합이 감소됩니다.This lessens the number of locked rows, thereby reducing contention between transactions.

  • 가능하면 보류 잠금과 같은 비관적 잠금 힌트를 사용하지 않습니다.Avoid pessimistic locking hints such as holdlock whenever possible. HOLDLOCK 또는 SERIALIZABLE 격리 수준과 같은 힌트를 사용하면 프로세스가 공유 잠금에서도 대기하여 동시성이 감소할 수 있습니다.Hints like HOLDLOCK or SERIALIZABLE isolation level can cause processes to wait even on shared locks and reduce concurrency

  • 가능하면 암시적 트랜잭션을 사용하지 않습니다. 암시적 트랜잭션의 특성 때문에 예기치 않은 동작이 발생할 수 있습니다.Avoid using Implicit transactions when possible Implicit transactions can introduce unpredictable behavior due to their nature. 암시적 트랜잭션 및 동시성 문제를 참조하세요.See Implicit Transactions and concurrency problems

  • 채우기 비율을 줄여 인덱스를 설계합니다. 채우기 비율을 줄이면 인덱스 페이지의 조각화를 방지하거나 줄여 특히 디스크에서 검색할 때 인덱스 검색 시간을 줄일 수 있습니다.Design indexes with a reduced fill factor Decreasing the fill factor may help you prevent or decrease fragmentation of index pages and thus reduce index seek times especially when retrieved from disk. 테이블 또는 뷰의 데이터와 인덱스에 대한 조각화 정보를 보려면 sys.dm_db_index_physical_stats를 사용합니다.To view fragmentation information for the data and indexes of a table or view, you can usesys.dm_db_index_physical_stats.

암시적 트랜잭션과 동시성 및 리소스 문제 방지Implicit transactions and avoiding concurrency and resource problems

동시성 문제와 리소스 문제를 방지하려면 암시적 트랜잭션을 신중하게 관리합니다.To prevent concurrency and resource problems, manage implicit transactions carefully. 암시적 트랜잭션을 사용할 때는 COMMIT 또는 ROLLBACK 다음의 Transact-SQLTransact-SQL 문이 자동으로 새 트랜잭션을 시작합니다.When using implicit transactions, the next Transact-SQLTransact-SQL statement after COMMIT or ROLLBACK automatically starts a new transaction. 이로 인해 애플리케이션에서 데이터를 찾아보는 동안이나 사용자 입력이 필요할 때 새 트랜잭션이 열릴 수 있습니다.This can cause a new transaction to be opened while the application browses through data, or even when it requires input from the user. 데이터 수정을 보호하는 데 필요한 마지막 트랜잭션을 완료한 다음 데이터 수정을 보호하기 위해 트랜잭션이 다시 한 번 필요할 때까지 암시적 트랜잭션을 해제합니다.After completing the last transaction required to protect data modifications, turn off implicit transactions until a transaction is once again required to protect data modifications. 이렇게 하면 애플리케이션에서 데이터를 찾아보고 사용자로부터 입력을 받는 동안 SQL Server 데이터베이스 엔진SQL Server Database Engine이 자동 커밋 모드를 사용할 수 있습니다.This process lets the SQL Server 데이터베이스 엔진SQL Server Database Engine use autocommit mode while the application is browsing data and getting input from the user.

또한 스냅샷 격리 수준을 사용하면 새 트랜잭션이 잠금을 확보하지 않더라도 장기 실행 트랜잭션이 tempdb에서 이전 버전이 제거되지 않도록 방지합니다.In addition, when the snapshot isolation level is enabled, although a new transaction will not hold locks, a long-running transaction will prevent the old versions from being removed from tempdb.

장기 실행 트랜잭션 관리Managing long-running transactions

장기 실행 트랜잭션 은 제때에 커밋되거나 롤백되지 않은 활성 트랜잭션입니다.A long-running transaction is an active transaction that has not been committed or roll backed the transaction in a timely manner. 예를 들어 트랜잭션의 시작과 끝을 사용자가 제어하는 경우에는 대개 사용자가 트랜잭션을 시작한 후 트랜잭션에서 사용자의 응답을 기다리는 동안 자리를 비울 때 장기 실행 트랜잭션이 발생합니다.For example, if the beginning and end of a transaction is controlled by the user, a typical cause of a long-running transaction is a user starting a transaction and then leaving while the transaction waits for a response from the user.

장기 실행 트랜잭션으로 인해 데이터베이스에 대해 다음과 같은 심각한 문제가 발생할 수 있습니다.A long running transaction can cause serious problems for a database, as follows:

  • 활성 트랜잭션이 커밋되지 않은 많은 수정 작업을 수행한 후에 서버 인스턴스가 종료되면 서버 인스턴스가 다시 시작된 후의 복구 단계 수행 시 recovery interval 서버 구성 옵션 또는 ALTER DATABASE ... SET TARGET_RECOVERY_TIME.If a server instance is shut down after an active transaction has performed many uncommitted modifications, the recovery phase of the subsequent restart can take much longer than the time specified by the recovery interval server configuration option or by the ALTER DATABASE ... SET TARGET_RECOVERY_TIME option. 이러한 옵션은 활성 검사점 및 간접 검사점의 빈도를 각각 지정합니다.These options control the frequency of active and indirect checkpoints, respectively. 검사점 형식에 대한 자세한 내용은 데이터베이스 검사점(SQL Server)을 참조하세요.For more information about the types of checkpoints, see Database Checkpoints (SQL Server).

  • 무엇보다도 대기 중인 트랜잭션은 로그를 거의 생성하지 않을 수 있지만 로그 잘림을 무한정 방해하여 트랜잭션 로그가 커져 가득 찰 수 있습니다.More importantly, although a waiting transaction might generate very little log, it holds up log truncation indefinitely, causing the transaction log to grow and possibly fill up. 트랜잭션 로그가 꽉 차면 데이터베이스에서 업데이트를 더 이상 수행할 수 없습니다.If the transaction log fills up, the database cannot perform any more updates. 자세한 내용은 SQL Server 트랜잭션 로그 아키텍처 및 관리 가이드, 전체 트랜잭션 로그 문제 해결(SQL Server Error 9002)트랜잭션 로그(SQL Server)를 참조하세요.For more information, see SQL Server Transaction Log Architecture and Management Guide, Troubleshoot a Full Transaction Log (SQL Server Error 9002), and The Transaction Log (SQL Server).

장기 실행 트랜잭션 검색Discovering long-running transactions

장기 실행 트랜잭션을 찾으려면 다음 중 하나를 사용합니다.To look for long-running transactions, use one of the following:

  • sys.dm_tran_database_transactionssys.dm_tran_database_transactions

    이 동적 관리 뷰는 데이터베이스 수준에서 트랜잭션 정보를 반환합니다.This dynamic management view returns information about transactions at the database level. 장기 실행 트랜잭션과 특히 관련된 열에는 첫 번째 로그 레코드 시간(database_transaction_begin_time), 현재 트랜잭션 상태(database_transaction_state), 트랜잭션 로그(database_transaction_begin_lsn)에서 시작 레코드의 LSN(로그 시퀀스 번호) 등이 있습니다.For a long-running transaction, columns of particular interest include the time of the first log record (database_transaction_begin_time), the current state of the transaction (database_transaction_state), and the log sequence number (LSN) of the begin record in the transaction log (database_transaction_begin_lsn).

    자세한 내용은 sys.dm_tran_database_transactions(Transact-SQL)를 참조하세요.For more information, see sys.dm_tran_database_transactions (Transact-SQL).

  • DBCC OPENTRAN

    이 문을 사용하면 트랜잭션 소유자의 사용자 ID를 식별할 수 있으므로 트랜잭션의 출처를 추적하여 롤백 대신 커밋을 더 많이 수행하는 순차적 종료 작업을 확인할 수 있습니다.This statement lets you identify the user ID of the owner of the transaction, so you can potentially track down the source of the transaction for a more orderly termination (committing it rather than rolling it back). 자세한 내용은 DBCC OPENTRAN(Transact-SQL)을 참조하세요.For more information, see DBCC OPENTRAN (Transact-SQL).

트랜잭션 중지Stopping a Transaction

KILL 문을 사용해야 하는 경우도 있습니다.You may have to use the KILL statement. 그러나 특히 중요한 프로세스가 실행 중일 때는 이 문을 신중하게 사용하십시오.Use this statement very carefully, however, especially when critical processes are running. 자세한 내용은 KILL(Transact-SQL)을 참조하세요.For more information, see KILL (Transact-SQL).

더 보기Additional Reading

행 버전 관리 오버헤드 Overhead of Row Versioning
확장 이벤트 Extended Events
sys.dm_tran_locks (Transact-SQL) sys.dm_tran_locks (Transact-SQL)
동적 관리 뷰 및 함수(Transact-SQL) Dynamic Management Views and Functions (Transact-SQL)
트랜잭션 관련 동적 관리 뷰 및 함수(Transact-SQL)Transaction Related Dynamic Management Views and Functions (Transact-SQL)