Transactions with Memory-Optimized TablesTransactions with Memory-Optimized Tables

이 항목은 다음에 적용됩니다. 예SQL Server(2016부터)예Azure SQL Database아니요Azure SQL Data Warehouse아니요병렬 데이터 웨어하우스 THIS TOPIC APPLIES TO: yesSQL Server (starting with 2016)yesAzure SQL DatabasenoAzure SQL Data Warehouse noParallel Data Warehouse

이 문서에서는 메모리 액세스에 최적화된 테이블 및 고유하게 컴파일된 저장 프로시저에 관련된 트랜잭션의 모든 측면을 설명합니다.This article describes all the aspects of transactions that are specific to memory-optimized tables and natively compiled stored procedures.

SQL Server의 트랜잭션 격리 수준은 메모리 액세스에 최적화된 테이블과 디스크 기반 테이블에 서로 다르게 적용되며 기본 메커니즘이 서로 다릅니다.The transaction isolation levels in SQL Server apply differently to memory-optimized tables versus disk-based tables, and the underlying mechanisms are different. 이러한 차이점을 이해하면 프로그래머가 처리량이 높은 시스템을 디자인하는 데 도움이 됩니다.An understanding of the differences helps the programmer design a high throughput system. 트랜잭션 무결성의 목표는 모든 경우에서 공유됩니다.The goal of transaction integrity is shared in all cases.

메모리 액세스에 최적화된 테이블의 트랜잭션에 대한 오류 조건을 보려면 충돌 검색 및 다시 시도 논리섹션을 참조하세요.For error conditions specific to transactions on memory-optimized tables, jump to the section Conflict Detection and Retry Logic.

일반적인 정보는 SET TRANSACTION ISOLATION LEVEL(Transact-SQL)을 참조하세요.For general information, see SET TRANSACTION ISOLATION LEVEL (Transact-SQL).

비관적 및 낙관적Pessimistic versus Optimistic

기능 차이는 트랜잭션 무결성에 대한 비관적 접근 방식과 낙관적 접근 방식으로 인해 발생합니다.The functional differences are due to pessimistic versus optimistic approaches to transaction integrity. 메모리 액세스에 최적화된 테이블은 낙관적 접근 방식을 사용합니다.Memory-optimized tables use the optimistic approach:

  • 비관적 접근 방식에서는 잠금을 사용하여 잠재적 충돌을 사전에 차단합니다.Pessimistic approach uses locks to block potential conflicts before they occur. 문을 실행할 때 잠금이 설정되고 트랜잭션이 커밋될 때 해제됩니다.Lock are taken when the statement is executed, and released when the transaction is committed.

  • 커밋 시 유효성 검사가 발생 및 수행되면 낙관적 접근 방식에서 충돌을 감지합니다.Optimistic approach detects conflicts as the occur and performs validation checks at commit time.

    • 오류 1205 교착 상태는 메모리 액세스에 최적화된 테이블에 발생할 수 없습니다.Error 1205, a deadlock, cannot occur for a memory-optimized table.

낙관적 접근 방식은 오버헤드가 적고 일반적으로 보다 효율적입니다. 대부분의 응용 프로그램에서 트랜잭션 충돌이 거의 발생하지 않기 때문입니다.The optimistic approach is less overhead and is usually more efficient, partly because transaction conflicts are uncommon in most applications. 낙관적 접근 방식과 비관적 접근 방식 간의 주요 기능 차이점은 충돌이 발생할 경우 비관적 접근 방식에서는 대기하고 낙관적 접근 방식에서는 트랜잭션 중 하나가 실패하므로 클라이언트에서 다시 시도해야 한다는 점입니다.The main functional difference between the pessimistic and optimistic approaches is that if a conflict occurs, in the pessimistic approach you wait, while in the optimistic approach one of the transactions fails and needs to be retried by the client. 기능 차이는 REPEATABLE READ 격리 수준이 적용되는 경우에 더 크고 SERIALIZABLE 수준에서 가장 큽니다.The functional differences are bigger when the REPEATABLE READ isolation level is in force, and are biggest for the SERIALIZABLE level.

트랜잭션 시작 모드Transaction Initiation Modes

SQL Server에는 다음과 같은 트랜잭션 시작 모드가 있습니다.SQL Server has the following modes for transaction initiation:

  • 자동 커밋 - 단순 쿼리 또는 DML 문의 시작 시 암시적으로 트랜잭션이 열리고 문 종료 시 암시적으로 트랜잭션이 커밋됩니다.Autocommit - The start of a simple query or DML statement implicitly opens a transaction, and the end of the statement implicitly commits the transaction. 기본값입니다.This is the default.

    • 자동 커밋 모드에서는 일반적으로 FROM 절에서 메모리 액세스에 최적화된 테이블의 트랜잭션 격리 수준에 대한 테이블 힌트를 코딩할 필요가 없습니다.In autocommit mode, usually you are not required to code a table hint about the transaction isolation level on the memory-optimized table in the FROM clause.
  • 명시적 - TRANSACT-SQL에는 최종 COMMIT TRANSACTION과 함께 BEGIN TRANSACTION 코드가 포함됩니다.Explicit - Your Transact-SQL contains the code BEGIN TRANSACTION, along with an eventual COMMIT TRANSACTION. 둘 이상의 문을 동일한 트랜잭션에 포함할 수 있습니다.Two or more statements statements can be corralled into the same transaction.

    • 명시적 모드에서는 데이터베이스 옵션 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT을 사용하거나 FROM 절에서 메모리 액세스에 최적화된 테이블의 트랜잭션 격리 수준에 대한 테이블 힌트를 코딩해야 합니다.In explicit mode, you must either use the database option MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT or code a table hint about the transaction isolation level on the memory-optimized table in the FROM clause.
  • 암시적 - SET IMPLICIT_TRANSACTION ON이 적용되는 경우입니다.Implicit - When SET IMPLICIT_TRANSACTION ON is in force. 이 옵션은 모두 0 = @@trancount인 경우 각 UPDATE 문 전에 명시적 BEGIN TRANSACTION에 해당하는 작업을 암시적으로 수행하기 때문에 IMPLICIT_BEGIN_TRANSACTION이 더 나은 이름일 수 있습니다.Perhaps a better name would have been IMPLICIT_BEGIN_TRANSACTION, because all this option does is implicitly perform the equivalent of an explicit BEGIN TRANSACTION before each UPDATE statement if 0 = @@trancount.</span></span> 따라서 최종적으로 명시적 COMMIT TRANSACTION을 실행하는 것은 사용자의 T-SQL 코드에 달려 있습니다.Therefore it is up to your T-SQL code to eventually issue an explicit COMMIT TRANSACTION.

  • ATOMIC 블록 - ATOMIC 블록의 모든 문은 고유하게 컴파일된 저장 프로시저에 필요하며 항상 단일 트랜잭션의 일부로 실행됩니다. ATOMIC 블록의 동작이 전체적으로 커밋되거나 실패할 경우 모두 롤백됩니다.ATOMIC BLOCK - All statements in ATOMIC blocks, which are required with natively compiled stored procedures, always run as part of a single transaction - either the actions of the atomic block as a whole are committed, or they are all rolled back, in case of a failure.

명시적 모드의 코드 예제Code Example with Explicit Mode

다음 해석된 TRANSACT-SQL 스크립트에서는 아래 항목을 사용합니다.The following interpreted Transact-SQL script uses:

  • 명시적 트랜잭션An explicit transaction.

  • dbo.Order_mo라는 메모리 액세스에 최적화된 테이블A memory-optimized table, named dbo.Order_mo.

  • READ COMMITTED 트랜잭션 격리 수준 컨텍스트The READ COMMITTED transaction isolation level context.

따라서 메모리 액세스에 최적화된 테이블에 대한 테이블 힌트가 필요합니다.Therefore it is necessary to have a table hint on the memory-optimized table. 힌트는 SNAPSHOT에 대한 것이거나 보다 더 격리된 수준이어야 합니다.The hint must be for SNAPSHOT or an even more isolating level. 코드 예제의 경우 힌트는 WITH(SNAPSHOT)입니다.In the case of the code example, the hint is WITH (SNAPSHOT). 이 힌트를 제거하면 스크립트에서 41368 오류가 발생하며 이 경우 자동화된 다시 시도는 적합하지 않습니다.If this hint is removed, the script would suffer an error 41368, for which an automated retry would be inappropriate:

  • 41368: READ COMMITTED 격리 수준을 사용한 메모리 액세스에 최적화된 테이블 액세스는 자동 커밋 트랜잭션에서만 지원됩니다.41368: Accessing memory optimized tables using the READ COMMITTED isolation level is supported only for autocommit transactions. 명시적 또는 암시적 트랜잭션에서는 지원되지 않습니다.It is not supported for explicit or implicit transactions. WITH(SNAPSHOT) 같은 테이블 힌트를 사용하여 메모리 액세스에 최적화된 테이블에 대해 지원되는 격리 수준을 제공합니다.Provide a supported isolation level for the memory-optimized table using a table hint, such as WITH (SNAPSHOT).
<span data-ttu-id="23128-143">SET TRANSACTION ISOLATION LEVEL READ COMMITTED;</span><span class="sxs-lookup"><span data-stu-id="23128-143">SET TRANSACTION ISOLATION LEVEL READ COMMITTED;</span></span>  
<span data-ttu-id="23128-144">GO</span><span class="sxs-lookup"><span data-stu-id="23128-144">GO</span></span>  

<span data-ttu-id="23128-145">BEGIN TRANSACTION;  -- Explicit transaction.</span><span class="sxs-lookup"><span data-stu-id="23128-145">BEGIN TRANSACTION;  -- Explicit transaction.</span></span>  

  -- Order_mo  is a memory-optimized table.  
<span data-ttu-id="23128-146">SELECT *</span><span class="sxs-lookup"><span data-stu-id="23128-146">SELECT *</span></span>  
   <span data-ttu-id="23128-147">FROM</span><span class="sxs-lookup"><span data-stu-id="23128-147">FROM</span></span>  
            <span data-ttu-id="23128-148">dbo.Order_mo  as o  WITH (SNAPSHOT)  -- Table hint.</span><span class="sxs-lookup"><span data-stu-id="23128-148">dbo.Order_mo  as o  WITH (SNAPSHOT)  -- Table hint.</span></span>  
       <span data-ttu-id="23128-149">JOIN dbo.Customer  as c  on c.CustomerId = o.CustomerId;</span><span class="sxs-lookup"><span data-stu-id="23128-149">JOIN dbo.Customer  as c  on c.CustomerId = o.CustomerId;</span></span>  

<span data-ttu-id="23128-150">COMMIT TRANSACTION;</span><span class="sxs-lookup"><span data-stu-id="23128-150">COMMIT TRANSACTION;</span></span>  

데이터베이스 옵션 WITH (SNAPSHOT) 을 사용할 경우 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT힌트를 사용하지 않아도 됩니다.Note that the need for the WITH (SNAPSHOT) hint can be avoided through the use of the database option MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT. 이 옵션이 ON으로 설정되면 더 낮은 격리 수준에서 메모리 액세스에 최적화된 테이블의 격리 수준이 자동으로 SNAPSHOT 격리로 승격됩니다.When this option is set to ON, access to a memory-optimized table under a lower isolation level is automatically elevated to SNAPSHOT isolation.

ALTER DATABASE CURRENT SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT=ON  

행 버전 관리Row Versioning

메모리 액세스에 최적화된 테이블에서는 가장 엄격한 격리 수준(SERIALIZABLE)에서도 난관적 접근 방식이 효율적인 매우 정교한 행 버전 관리 시스템을 사용합니다.Memory-optimized tables use a highly sophisticated row versioning system that makes the optimistic approach efficient, even at the most strict isolation level of SERIALIZABLE. 자세한 내용은 메모리 액세스에 최적화된 테이블 소개를 참조하세요.For details see Introduction to Memory-Optimized Tables.

디스크 기반 테이블에서는 READ_COMMITTED_SNAPSHOT 또는 SNAPSHOT 격리 수준이 적용되는 경우 행 버전 관리 시스템이 간접적으로 적용됩니다.Disk-based tables indirectly have a row versioning system when READ_COMMITTED_SNAPSHOT or the SNAPSHOT isolation level is in effect. 이 시스템은 tempdb를 기반으로 하며 최대 효율성을 위해 메모리 액세스에 최적화된 데이터 구조에는 행 버전 관리가 기본 적용됩니다.This system is based on tempdb, while memory-optimized data structures have row versioning built-in, for maximum efficiency.

격리 수준Isolation Levels

다음 표에는 가능한 트랜잭션 격리 수준이 오름차순으로 나열되어 있습니다.The following table lists the possible levels of transaction isolation, in sequence from least isolation to most. 발생할 수 있는 충돌 및 이러한 충돌을 처리하는 재시도 논리에 대한 자세한 내용은 충돌 검색 및 다시 시도 논리를 참조하세요.For details about conflicts that can occur and retry logic to deal with these conflicts, see Conflict Detection and Retry Logic.

격리 수준Isolation Level 설명Description
READ UNCOMMITTEDREAD UNCOMMITTED 사용할 수 없음: 커밋되지 않은 격리에서는 메모리 액세스에 최적화된 테이블에 액세스할 수 없습니다.Not available: memory-optimized tables cannot be accessed under Read Uncommitted isolation. 세션 수준 TRANSACTION ISOLATION LEVEL이 READ UNCOMMITTED로 설정된 경우 WITH (SNAPSHOT) 테이블 힌트를 사용하거나 데이터베이스 설정 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT을 ON으로 설정하여 SNAPSHOT 격리의 메모리 액세스에 최적화된 테이블에 액세스할 수 있습니다.It is still possible to access memory-optimized tables under SNAPSHOT isolation if the session-level TRANSACTION ISOLATION LEVEL is set to READ UNCOMMITTED, by using the WITH (SNAPSHOT) table hint or setting the database setting MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT to ON.
READ COMMITTEDREAD COMMITTED 자동 커밋 모드가 적용되는 경우에만 메모리 액세스에 최적화된 테이블에 지원됩니다.Supported for memory-optimized tables only when the autocommit mode is in effect. 세션 수준 TRANSACTION ISOLATION LEVEL이 READ COMMITTED로 설정된 경우 WITH (SNAPSHOT) 테이블 힌트를 사용하거나 데이터베이스 설정 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT을 ON으로 설정하여 SNAPSHOT 격리의 메모리 액세스에 최적화된 테이블에 액세스할 수 있습니다.It is still possible to access memory-optimized tables under SNAPSHOT isolation if the session-level TRANSACTION ISOLATION LEVEL is set to READ COMMITTED, by using the WITH (SNAPSHOT) table hint or setting the database setting MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT to ON.

데이터베이스 옵션 READ_COMMITTED_SNAPSHOT이 ON으로 설정된 경우 동일한 문에서 READ COMMITTED 격리의 메모리 액세스에 최적화된 테이블 및 디스크 기반 테이블에 액세스할 수 없습니다.Note that if the database option READ_COMMITTED_SNAPSHOT is set to ON, it is not allowed to access both a memory-optimized and a disk-based table under READ COMMITTED isolation in the same statement.
SNAPSHOTSNAPSHOT 메모리 액세스에 최적화된 테이블에 지원됩니다.Supported for memory-optimized tables.

내부적으로 SNAPSHOT은 메모리 액세스에 최적화된 테이블에 가장 덜 까다로운 트랜잭션 격리 수준입니다.Internally SNAPSHOT is the least demanding transaction isolation level for memory-optimized tables.

SNAPSHOT은 REPEATABLE READ 또는 SERIALIZABLE보다 더 적은 시스템 리소스를 사용합니다.SNAPSHOT uses fewer system resources than does REPEATABLE READ or SERIALIZABLE.
REPEATABLE READREPEATABLE READ 메모리 액세스에 최적화된 테이블에 지원됩니다.Supported for memory-optimized tables. REPEATABLE READ 격리를 사용하면 커밋 시 동시 트랜잭션이 이 트랜잭션에서 읽은 행을 업데이트하지 않습니다.The guarantee provided by REPEATABLE READ isolation is that, at commit time, no concurrent transaction has updated any of the rows read by this transaction.

낙관적 모델로 인해 동시 트랜잭션이 이 트랜잭션에서 읽은 행을 업데이트하는 것을 방지할 수 없습니다.Because of the optimistic model, concurrent transactions are not prevented from updating rows read by this transaction. 대신, 이 트랜잭션은 커밋 시 REPEATABLE READ 격리를 위반하지 않는지 확인합니다.Instead, at commit time this transaction validated that REPEATABLE READ isolation has not been violated. REPEATABLE READ 격리를 위반하는 경우 이 트랜잭션이 롤백되므로 다시 시도해야 합니다.If it has, this transaction is rolled back and must be retried.
SERIALIZABLESERIALIZABLE 메모리 액세스에 최적화된 테이블에 지원됩니다.Supported for memory-optimized tables.

Serializable 이라고 명명된 것은 트랜잭션이 동시에 실행되는 것이 아니라 연속적으로 실행되는 것과 유사할 정도로 격리가 엄격하기 때문입니다.Named Serializable because the isolation is so strict that it is almost a bit like having the transactions run in series rather than concurrently.

트랜잭션 단계 및 수명Transaction Phases and Lifetime

메모리 액세스에 최적화된 테이블이 포함된 경우 트랜잭션 수명은 다음 이미지에 표시된 단계를 거칩니다.When a memory-optimized table is involved, the lifetime of a transaction progresses through the phases as displayed in the following image.

hekaton_transactions

단계에 대한 설명은 다음과 같습니다.Descriptions of the phases follow.

일반 처리: 1/3단계Regular Processing: Phase 1 (of 3)

  • 이 단계는 모든 쿼리 및 쿼리의 DML 문 실행으로 구성됩니다.This phase is comprised of the execution of all queries and DML statements in the query.
  • 이 단계에서 문은 메모리 액세스에 최적화된 테이블 버전을 트랜잭션의 논리적 시작 시간으로 간주합니다.During this phase, the statements see the version of the memory-optimized tables as of the logical start time of the transaction.

유효성 검사: 2/3단계Validation: Phase 2 (of 3)

  • 끝 시간이 지정되어 트랜잭션이 논리적으로 완료된 것으로 표시되면 유효성 검사 단계가 시작됩니다.The validation phase begins by assigning the end time, thereby marking the transaction as logically complete. 이 경우 트랜잭션의 모든 변경을 다른 트랜잭션에서 볼 수 있게 되므로 이 트랜잭션에 종속되며 이 트랜잭션이 커밋될 때까지 커밋할 수 없게 됩니다.This makes all changes of the transaction visible to other transactions, which will take a dependency on this transaction, and will not be allowed to commit until this transaction has successfully committed. 또한 이러한 종속성을 갖는 트랜잭션에서는 결과 집합을 클라이언트로 반환할 수 없어 클라이언트에서는 데이터베이스에 성공적으로 커밋된 데이터만 볼 수 있습니다.In addition, transactions which hold such dependencies are not allowed to return result sets to the client to ensure the client only sees data that has been successfully committed to the database.
  • 이 단계는 반복 읽기 및 직렬화 유효성 검사로 구성됩니다.This phase comprises the repeatable read and serializable validation. 반복 읽기 유효성 검사에서는 트랜잭션에 의한 행 읽기가 업데이트되었는지 검사합니다.For repeatable read validation it checks whether any of the rows read by the transaction has since been updated. 직렬화 유효성 검사에서는 이 트랜잭션에 의해 스캔된 데이터 범위로 행이 삽입되었는지 검사합니다.For serializable validation it checks whether any row has been inserted into any data range scanned by this transaction. 스냅샷 격리를 사용할 경우 격리 수준 및 충돌의 테이블당 반복 읽기 및 직렬화 유효성 검사가 발생하여 고유 및 외래 키 제약 조건의 일관성을 검사할 수 있습니다.Note that, per the table in Isolation Levels and Conflicts, both repeatable read and serializable validation can happen when using snapshot isolation, to validate consistency of unique and foreign key constraints.

커밋 처리: 3/3단계Commit Processing: Phase 3 (of 3)

  • 이 커밋 단계 중에는 지속형 테이블의 변경 내용이 로그에 기록되고 로그는 디스크에 기록됩니다.During the commit phase, the changes to durable tables are written to the log, and the log is written to disk. 그런 다음 제어 권한이 클라이언트에 반환됩니다.Then control is returned to the client.
  • 커밋 처리가 완료되면 모든 종속 트랜잭션에 커밋이 가능하다는 알림이 전달됩니다.After commit processing completes, all dependent transactions are notified that they can commit.

항상 작업의 트랜잭션 단위를 데이터 요구 사항에 유효한 최소 단위로 간략하게 유지해야 합니다.As always, you should try to keep your transactional units of work as minimal and brief as is valid for your data needs.

충돌 검색 및 다시 시도 논리Conflict Detection and Retry Logic

트랜잭션 실패 및 롤백이 발생할 수 있는 트랜잭션 관련 오류 조건은 두 가지입니다.There are two kinds of transaction-related error conditions that cause a transaction to fail and roll back. 대부분의 경우 이러한 오류가 발생하면 교착 상태가 발생할 때와 마찬가지로 트랜잭션을 다시 시도해야 합니다.In most cases, once such a failure occurs, the transaction needs to be retried, similar to when a deadlock occurs.

  • 동시 트랜잭션 간 충돌.Conflicts between concurrent transactions. 이는 업데이트 충돌 및 유효성 검사 실패이며 트랜잭션 격리 수준 위반 또는 제약 조건 위반이 원인일 수 있습니다.These are update conflicts and validation failures, and can be due to transaction isolation level violations or constraint violations.
  • 종속성 오류.Dependency failures. 종속된 트랜잭션의 커밋이 실패하거나 종속 수가 너무 많이 늘어나서 발생하는 오류입니다.These result from transaction you depend on failing to commit, or the number of dependencies growing too large.

다음은 메모리 액세스에 최적화된 테이블에 액세스하는 트랜잭션이 실패할 수 있는 오류 조건입니다.Below are the error conditions that can cause transactions accessing memory-optimized tables to fail.

오류 코드Error Code 설명Description 원인Cause
4130241302 현재 트랜잭션이 시작된 이후 다른 트랜잭션에서 업데이트된 행을 업데이트하려고 했습니다.Attempted to update a row that was updated in a different transaction since the start of the present transaction. 이 오류 조건은 두 개의 동시 트랜잭션에서 같은 행을 동시에 업데이트 또는 삭제하려고 할 때 발생합니다.This error condition occurs if two concurrent transactions attempt to update or delete the same row at the same time. 두 개의 트랜잭션 중 하나에 이 오류 메시지가 전달되며 다시 시도해야 합니다.One of the two transactions receives this error message and will need to be retried.

4130541305 반복 가능한 읽기 유효성 검사 오류.Repeatable read validation failure. 메모리 액세스에 최적화된 테이블에서 행을 읽었는데 이 트랜잭션을 커밋하기 전에 커밋된 다른 트랜잭션에 의해 이 트랜잭션이 업데이트되었습니다.A row read from a memory-optimized table this transaction has been updated by another transaction that has committed before the commit of this transaction. 이 오류는 REPEATABLE READ 또는 SERIALIZABLE 격리를 사용하거나 동시 트랜잭션의 작업으로 인해 FOREIGN KEY 제약 조건의 위반이 발생하는 경우에도 발생할 수 있습니다.This error can occur when using REPEATABLE READ or SERIALIZABLE isolation, and also if the actions of a concurrent transaction cause violation of a FOREIGN KEY constraint.

이러한 FOREIGN KEY 제약 조건의 동시 위반은 일반적으로 드물게 발생하며 응용 프로그램 논리 또는 데이터 입력에 문제가 있다는 것을 나타냅니다.Such concurrent violation of foreign key constraints is usually rare, and typically indicates an issue with the application logic or with data entry. 그러나 FOREIGN KEY 제약 조건과 관련된 열에 인덱스가 없는 경우에도 오류가 발생할 수 있습니다.However, the error can also occur if there is no index on the columns involved with the FOREIGN KEY constraint. 따라서 항상 메모리 액세스에 최적화된 테이블의 외래 키 열에 인덱스를 만들어야 합니다.Therefore, the guidance is to always create an index on foreign key columns in a memory-optimized table.

외래 키 위반으로 인해 발생한 유효성 검사 오류에 대한 자세한 고려 사항은 SQL Server 고객 자문 팀의 이 블로그 게시물 을 참조하세요.For more detailed considerations about validation failures caused by foreign key violations, see this blog post by the SQL Server Customer Advisory Team.
4132541325 직렬화 유효성 검사 오류.Serializable validation failure. 현재 트랜잭션에서 이전에 검색한 범위에 새 행을 삽입했습니다.A new row was inserted into a range that was scanned earlier by the present transaction. 이를 가상 행이라고 합니다.We call this a phantom row. 이 오류는 SERIALIZABLE 격리를 사용하거나 동시 트랜잭션의 작업으로 인해 PRIMARY KEY, UNIQUE 또는 FOREIGN KEY 제약 조건의 위반이 발생하는 경우 발생할 수 있습니다.This error can occur when using SERIALIZABLE isolation, and also if the actions of a concurrent transaction cause violation of a PRIMARY KEY, UNIQUE, or FOREIGN KEY constraint.

이러한 동시 제약 조건의 위반은 일반적으로 드물게 발생하며 응용 프로그램 논리 또는 데이터 입력에 문제가 있다는 것을 의미합니다.Such concurrent constraint violation is usually rare, and typically indicates an issue with the application logic or data entry. 그러나 이 오류는 반복 읽기 유효성 검사 오류와 마찬가지로 관련 열에 인덱스가 없는 FOREIGN KEY 제약 조건이 있는 경우에도 발생할 수 있습니다.However, similar to repeatable read validation failures, this error can also occur if there is a FOREIGN KEY constraint with no index on the columns involved.
4130141301 종속성 오류: 나중에 커밋이 실패한 다른 트랜잭션에 종속되어 있습니다.Dependency failure: a dependency was taken on another transaction that later failed to commit. 이 트랜잭션(Tx1)은 다른 트랜잭션(Tx2)에 종속되어 있는데 해당 트랜잭션(Tx2)이 Tx2에서 쓰여진 데이터를 읽어 유효성 검사 또는 커밋 처리 단계였습니다.This transaction (Tx1) took a dependency on another transaction (Tx2) while that transaction (Tx2) was in its validation or commit processing phase, by reading data that was written by Tx2. 이후에 Tx2 커밋에 실패했습니다.Tx2 subsequently failed to commit. Tx2가 커밋에 실패하는 가장 일반적인 원인은 반복 읽기(41305) 및 직렬화(41325) 유효성 검사 실패이며 그 외에 로그 IO 실패 등이 있습니다.Most common causes for Tx2 to fail to commit are repeatable read (41305) and serializable (41325) validation failures; a less common cause is log IO failure.
4183941839 트랜잭션이 최대 커밋 종속성 수를 초과했습니다.Transaction exceeded the maximum number of commit dependencies. 특정 트랜잭션(Tx1)이 종속될 수 있는 트랜잭션 수에는 제한이 있습니다. 이러한 종속성을 나가는 종속성이라고 합니다.There is a limit on the number transactions a given transaction (Tx1) can depend on - those are the outgoing dependencies. 또한 특정 트랜잭션(Tx1)에 종속될 수 있는 트랜잭션 수에도 제한이 있는데 이를 들어오는 종속성이라고 합니다.In addition, there is a limit on the number of transactions that can depend on a given transaction (Tx1) - these are the incoming dependencies. 두 제한 모두 8입니다.The limit for both is 8.

이 오류는 일반적으로 단일 쓰기 트랜잭션에서 쓴 데이터에 액세스하는 읽기 트랜잭션 수가 많은 경우 발생합니다.The most common case for this failure is where there is a large number of read transactions accessing data written by a single write transaction. 읽기 트랜잭션이 모두 동일한 데이터의 대량 스캔을 수행하고 쓰기 트랜잭션의 커밋 처리 또는 유효성 검사 시간이 긴 경우 이 조건을 만족시킬 가능성이 높아집니다. 예를 들어 쓰기 트랜잭션이 직렬화 격리에서 많은 스캔을 수행하거나(유효성 검사 단계의 길이가 늘어남) 트랜잭션 로그가 속도가 느린 로그 IO 장치에 저장될 때(커밋 처리 길이가 길어짐) 발생합니다.The likelihood of hitting this condition increases if the read transactions are all performing large scans of the same data and if validation or commit processing of the write transaction takes long, for example the write transaction performs large scans under serializable isolation (increases length of the validation phase) or the transaction log is placed on a slow log IO device (increases length of commit processing). 읽기 트랜잭션이 대량 스캔을 수행하고 몇 개의 행만 액세스해야 하는 경우 인덱스 누락을 의미할 수 있습니다.If the read transactions are performing large scans and they are expected to access only few rows, this could be an indication of a missing index. 마찬가지로 쓰기 트랜잭션에서 직렬화 격리를 사용하고 대량 스캔을 수행하지만 몇 개의 행만 액세스해야 하는 경우에도 인덱스 누락을 의미할 수 있습니다.Similarly, if the write transaction uses serializable isolation and is performing large scans but is expected to access only few rows, this is also an indication of a missing index.

커밋 종속성 수에 대한 제한은 추적 플래그 9926을 사용하여 늘릴 수 있습니다.The limit on number of commit dependencies can be lifted by use Trace Flag 9926. 위에서 언급한 경우에서 이러한 문제를 마스킹할 수 있으므로 이 추적 플래그는 인덱스 누락이 없는 것을 확인한 후 이 오류 조건을 만족하는 경우에만 사용합니다.Use this trace flag only if you are still hitting this error condition after confirming that there are no missing indexes, as it could mask these issues in the above-mentioned cases. 또 다른 주의 사항은 복잡한 종속성 그래프입니다. 각 트랜잭션에 들어오는 종속성과 나가는 종속성이 많고 개별 트랜잭션에 많은 종속성 계층이 있으면 시스템의 효율성이 저하될 수 있습니다.Another caution is that complex dependency graphs, where each transaction has a large number of incoming as well as outgoing dependencies, and individual transactions have many layers of dependencies, can lead to inefficiencies in the system.

재시도 논리Retry Logic

위에서 언급한 조건으로 인해 트랜잭션이 실패하면 트랜잭션이 재시도되어야 합니다.When a transaction fails due to any of the above-mentioned conditions, the transaction should be retried.

클라이언트 또는 서버 쪽에서 재시도 논리를 구현할 수 있습니다.Retry logic can be implemented at the client or server side. 일반적인 권장 사항은 클라이언트 쪽에서 재시도 논리를 구현하는 것입니다. 이 방법이 더 효율적이며 실패가 발생하기 전에 트랜잭션에서 반환된 결과 집합을 처리할 수 있기 때문입니다.The general recommendation is to implement retry logic on the client side, as it is more efficient, and allows you to deal with result sets returned by the transaction before the failure occurs.

다시 시도 T-SQL 코드 예제Retry T-SQL Code Example

재시도할 경우 예상하지 않은 클라이언트로 추가 결과 집합이 반환될 수 있기 때문에 T-SQL을 사용하는 서버 쪽 재시도 논리는 클라이언트로 결과 집합을 반환하지 않는 트랜잭션에만 사용해야 합니다.Server-side retry logic using T-SQL should only be used for transactions that do not return result sets to the client, since retries can potentially result on additional result sets being returned to the client that may not be anticipated.

다음 해석된 T-SQL 스크립트는 메모리 액세스에 최적화된 테이블을 포함하는 트랜잭션 충돌과 관련된 오류에 대한 다시 시도 논리를 보여 줍니다.The following interpreted T-SQL script illustrates what retry logic can look like for the errors associated with transaction conflicts involving memory-optimized tables.

  -- Retry logic, in Transact-SQL.  
DROP PROCEDURE If Exists usp_update_salesorder_dates;  
GO  

CREATE PROCEDURE usp_update_salesorder_dates  
AS  
BEGIN  
    DECLARE @retry INT = 10;  

    WHILE (@retry > 0)  
    BEGIN  
        BEGIN TRY  
            BEGIN TRANSACTION;  

            UPDATE dbo.SalesOrder_mo WITH (SNAPSHOT)  
                set OrderDate = GetUtcDate()  
                where CustomerId = 42;  

            UPDATE dbo.SalesOrder_mo WITH (SNAPSHOT)  
                set OrderDate = GetUtcDate()  
                where CustomerId = 43;  

            COMMIT TRANSACTION;  
            SET @retry = 0;  -- //Stops the loop.  
        END TRY  

        BEGIN CATCH  
            SET @retry -= 1;  

            IF (@retry > 0 AND  
                ERROR_NUMBER() in (41302, 41305, 41325, 41301, 41839, 1205)  
                )  
            BEGIN  
                IF XACT_STATE() = -1  
                    ROLLBACK TRANSACTION;  

                WAITFOR DELAY '00:00:00.001';  
            END  
            ELSE  
            BEGIN  
                PRINT 'Suffered an error for which Retry is inappropriate.';  
                THROW;  
            END  
        END CATCH  

    END -- //While loop  
END;  
GO  

  --  EXECUTE usp_update_salesorder_dates;  

크로스 컨테이너 트랜잭션Cross-Container Transaction

트랜잭션이 다음을 수행하는 경우 크로스 컨테이너 트랜잭션이라고 합니다.A transaction is called a cross-container transaction if it:

  • 해석된 Transact-SQL에서 메모리 액세스에 최적화된 테이블에 액세스하는 경우Accesses a memory-optimized table from interpreted Transact-SQL; or
  • 트랜잭션이 이미 열려 있을 때 기본 프로시저를 실행하는 경우(XACT_STATE() = 1)Executes a native proc when a transaction is already open (XACT_STATE() = 1).

"크로스 컨테이너"라는 용어는 트랜잭션이 두 트랜잭션 관리 컨테이너(디스크 기반 테이블용과 메모리 액세스에 최적화된 테이블용)에서 실행된다는 팩트에서 파생된 것입니다.The term "cross-container" derives from the fact that the transaction runs across the two transaction management containers, one for disk-based tables and one for memory-optimized tables.

단일 크로스 컨테이너 트랜잭션 내에서 디스크 기반 및 메모리 액세스에 최적화된 테이블에 액세스하기 위해 다른 격리 수준이 사용될 수 있습니다.Within a single cross-container transaction, different isolation levels can be used for accessing disk-based and memory-optimized tables. 이 차이점은 WITH (SERIALIZABLE) 등의 명시적 테이블 힌트 또는 데이터베이스 옵션 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT을 통해 표현됩니다. 이렇게 하면 TRANSACTION ISOLATION LEVEL이 READ COMMITTED 또는 READ UNCOMMITTED로 구성된 경우 메모리 액세스에 최적화된 테이블의 격리 수준이 명시적으로 스냅샷 수준으로 상승됩니다.This difference is expressed through explicit table hints such as WITH (SERIALIZABLE) or through the database option MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT, which implicitly elevates the isolation level for memory-optimized table to snapshot if the TRANSACTION ISOLATION LEVEL is configured as READ COMMITTED or READ UNCOMMITTED.

다음 Transact-SQL 코드 예제에서In the following Transact-SQL code example:

  • 디스크 기반 테이블 Table_D1은 READ COMMITTED 격리 수준을 사용하여 액세스됩니다.The disk-based table, Table_D1, is accessed using the READ COMMITTED isolation level.
  • 메모리 액세스에 최적화된 테이블 Table_MO7은 SERIALIZABLE 격리 수준을 사용하여 액세스됩니다.The memory-optimized table Table_MO7 is accessed using the SERIALIZABLE isolation level. 삽입이 항상 일관적이고 직렬화 격리에서 기본적으로 실행되므로 Table_MO6에는 특정 관련 격리 수준이 없습니다.Table_MO6 does not have a specific associated isolation level, since inserts are always consistent and executed essentially under serializable isolation.
  -- Different isolation levels for  
  -- disk-based tables versus memory-optimized tables,  
  -- within one explicit transaction.  

<span data-ttu-id="23128-268">SET TRANSACTION ISOLATION LEVEL READ COMMITTED;</span><span class="sxs-lookup"><span data-stu-id="23128-268">SET TRANSACTION ISOLATION LEVEL READ COMMITTED;</span></span>  
<span data-ttu-id="23128-269">GO</span><span class="sxs-lookup"><span data-stu-id="23128-269">go</span></span>  

<span data-ttu-id="23128-270">BEGIN TRANSACTION;</span><span class="sxs-lookup"><span data-stu-id="23128-270">BEGIN TRANSACTION;</span></span>  

    -- Table_D1 is a traditional disk-based table, accessed using READ COMMITTED isolation.  
    --  
    SELECT * FROM Table_D1;  



    -- Table_MO6 and Table_MO7 are memory-optimized tables. Table_MO7 is accessed using SERIALIZABLE isolation,  
<span data-ttu-id="23128-271">--   while Table_MO6 does not have a specific</span><span class="sxs-lookup"><span data-stu-id="23128-271">--   while Table_MO6 does not have a specific</span></span>   
    --  
    <span data-ttu-id="23128-272">INSERT Table_MO6</span><span class="sxs-lookup"><span data-stu-id="23128-272">INSERT Table_MO6</span></span>  
        <span data-ttu-id="23128-273">SELECT * FROM Table_MO7 WITH (SERIALIZABLE);</span><span class="sxs-lookup"><span data-stu-id="23128-273">SELECT * FROM Table_MO7 WITH (SERIALIZABLE);</span></span>  


<span data-ttu-id="23128-274">COMMIT TRANSACTION;</span><span class="sxs-lookup"><span data-stu-id="23128-274">COMMIT TRANSACTION;</span></span>  
<span data-ttu-id="23128-275">GO</span><span class="sxs-lookup"><span data-stu-id="23128-275">go</span></span>  

제한 사항Limitations

  • 데이터베이스간 트랜잭션은 메모리 액세스에 최적화된 테이블에 지원되지 않습니다.Cross-database transactions are not supported for memory-optimized tables. 트랜잭션이 메모리 액세스에 최적화된 테이블에 액세스하는 경우 다음을 제외하고는 다른 데이터베이스에 액세스할 수 없습니다.If a transaction accesses a memory-optimized table, the transaction cannot access any other database, except for:

    • tempdb 데이터베이스tempdb database.
    • 마스터 데이터베이스에서 읽기 전용Read-only from the master database.
  • 분산 트랜잭션은 지원되지 않습니다. BEGIN DISTRIBUTED TRANSACTION이 사용되는 경우 트랜잭션은 메모리 액세스에 최적화된 테이블에 액세스할 수 없습니다.Distributed transactions are not supported: When BEGIN DISTRIBUTED TRANSACTION is used, the transaction cannot access a memory-optimized table.

고유하게 컴파일된 저장 프로시저Natively Compiled Stored Procedures

  • 기본 프로시저에서 ATOMIC 블록은 다음과 같이 전체 블록에 대한 트랜잭션 격리 수준을 선언해야 합니다.In a native proc, the ATOMIC block must declare the transaction isolation level for the whole block, such as:

    • ... BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, ...) ...
  • 기본 프로시저 본문에는 명시적 트랜잭션 제어 문을 사용할 수 없습니다.No explicit transaction control statements are allowed within the body of a native proc. BEGIN TRANSACTION, ROLLBACK TRANSACTION 등은 모두 허용되지 않습니다.BEGIN TRANSACTION, ROLLBACK TRANSACTION and so on are all disallowed.

  • ATOMIC 블록을 사용한 트랜잭션 제어에 대한 자세한 내용은 Atomic 블록을 참조하세요.For more information about transaction control with ATOMIC blocks see Atomic Blocks