SQL Server ID 값을 순서대로 읽을 수 있습니까?


24

TL : DR : 아래 질문은 다음과 같이 요약됩니다. 행을 삽입 할 때 새 값 생성Identity 과 클러스터 된 인덱스에서 해당 행 키 잠금 사이에 기회 창이 있습니까? 외부 관찰자가 더 새로운 것을 볼 수 있습니다. Identity동시 거래에 의해 삽입 된 가치? (SQL Server에서)

상세 버전

테이블의 클러스터형 인덱스 (여러 개의 추가 비 클러스터형 인덱스도 있음)의 키인 Identity이라는 열 이있는 SQL Server 테이블 CheckpointSequence이 있습니다. 여러 개의 동시 프로세스 및 스레드에 의해 행이 테이블에 삽입 됩니다 (분리 레벨 READ COMMITTED에서 및 제외 IDENTITY_INSERT). 동시에, 클러스터형 인덱스에서 행을 주기적으로 읽는 프로세스가 있습니다 CheckpointSequence( 옵션이 해제 된 상태 에서 격리 레벨 READ COMMITTEDREAD COMMITTED SNAPSHOT있음).

저는 현재 읽기 프로세스가 체크 포인트를 "건너 뛰지"못한다는 사실에 의존하고 있습니다. 내 질문은 : 이 부동산에 의존 할 수 있습니까? 그렇지 않다면, 그것을 실현시키기 위해 어떻게해야합니까?

예 : ID 값이 1, 2, 3, 4 및 5 인 행을 삽입하는 경우 독자 값이 4 인 행을보기 전에 값이 5 인 행을 볼 수 없어야합니다 . 테스트는 ORDER BY CheckpointSequence절이 포함 된 쿼리 ( 그리고 WHERE CheckpointSequence > -1절), 4 행이있을 때마다 안정적으로 블록은 5 행이 이미 커밋 된 경우에도 읽을 수 있지만 아직 커밋하지합니다.

나는 적어도 이론 상으로는이 가정이 깨질 수있는 경쟁 조건이있을 수 있다고 생각합니다. 불행히도, on on documentation 은 여러 동시 트랜잭션의 컨텍스트에서 작동 Identity하는 Identity방식에 대해 많이 말하지 않으며 "현재 시드 및 증분을 기반으로 새로운 각 값이 생성됩니다"라고 말합니다. "특정 거래에 대한 각각의 새로운 가치는 테이블에있는 다른 동시 거래와 다릅니다." ( MSDN )

내 추론은 다음과 같이 작동해야합니다.

  1. 트랜잭션이 명시 적 또는 암시 적으로 시작됩니다.
  2. ID 값 (X)이 생성됩니다.
  3. 해당 행 잠금은 ID 값을 기반으로 클러스터형 인덱스에서 가져옵니다 (잠금 에스컬레이션이 시작되지 않는 경우 전체 테이블이 잠김).
  4. 행이 삽입됩니다.
  5. 트랜잭션이 커밋되어 (아마도 시간이 많이 걸릴 수 있음) 잠금이 다시 제거됩니다.

2 단계와 3 단계 사이에는 아주 작은 창이 있으며

  • 동시 세션은 다음 ID 값 (X + 1)을 생성하고 나머지 모든 단계를 실행할 수 있습니다.
  • 따라서 해당 시점에 정확하게 오는 리더가 X + 1 값을 읽을 수있게하여 X 값이 누락됩니다.

물론,이 확률은 매우 낮습니다. 그러나 여전히-일어날 수 있습니다. 아니면 할 수 있습니까?

컨텍스트에 관심이있는 경우 NEventStore의 SQL Persistence Engine 구현입니다. NEventStore는 모든 이벤트가 새로운 오름차순 체크 포인트 시퀀스 번호를 얻는 추가 전용 이벤트 저장소를 구현합니다. 클라이언트는 체크 포인트별로 정렬 된 이벤트 저장소에서 이벤트를 읽습니다. 검사 점이 X 인 이벤트가 처리되면 클라이언트는 "최신"이벤트, 즉 검사 점이 X + 1 이상인 이벤트 만 고려하므로 이벤트를 건너 뛸 수없는 것이 중요합니다. . 그들이 다시 고려하지 않을 거라고 나는 현재 여부를 결정하기 위해 노력하고있어 Identity. 기반의 체크 포인트의 구현이 요구 사항을 충족 이들은되어 사용되는 정확한 SQL 문 : 스키마 , 작가의 쿼리는 ,독자의 질문 .)

내가 옳고 위에서 설명한 상황이 발생할 수 있다면, 두 가지 옵션 중 두 가지만 만족할 수 있습니다.

  • X를보기 전에 체크 포인트 시퀀스 값 X + 1을 볼 때 X + 1을 닫고 나중에 다시 시도하십시오. 그러나 Identity물론 갭을 생성 할 수 있기 때문에 (예 : 트랜잭션이 롤백 될 때) X는 절대로 오지 않을 수 있습니다.
  • 따라서 동일한 접근 방식이지만 n 밀리 초 후에 간격을 허용하십시오. 그러나 어떤 n 값을 가정해야합니까?

더 좋은 아이디어가 있습니까?


신원 대신 시퀀스를 사용해 보셨습니까? ID를 사용하면 어떤 삽입물이 특정 ID 값을 얻을지 확실하게 예측할 수는 없지만 시퀀스를 사용하는 데 문제가되지는 않습니다. 물론 그것은 당신이 지금하는 일을 변화시킵니다.
Antoine Hernandez

@SoleDBAGuy 시퀀스가 ​​위에서 설명한 경쟁 조건을 더욱 가능성있게 만들지 않습니까? 새 시퀀스 값 X를 생성하고 (위의 2 단계 대체) 행을 삽입합니다 (3 및 4 단계). 2와 3 사이에 다른 누군가가 다음 시퀀스 값 X + 1을 생성하고 커밋 할 수 있으며 독자는 시퀀스 값 X로 행을 삽입하기 전에 해당 값 X + 1을 읽습니다.
Fabian Schmied

답변:


26

행을 삽입 할 때 외부 ID가 동시 트랜잭션에 의해 삽입 된 새로운 ID 값을 볼 수있는 클러스터 된 인덱스에서 새 ID 값 생성과 해당 행 키 잠금 사이에 기회 창이 있습니까?

예.

아이디 값할당은 포함하는 사용자 트랜잭션과 무관합니다 . 트랜잭션이 롤백 되더라도 ID 값이 사용되는 이유 중 하나입니다. 증분 작업 자체는 손상을 방지하기 위해 래치로 보호되지만 이는 보호 범위입니다.

구현의 특정 상황에서 ID 할당 (에 대한 호출 CMEDSeqGen::GenerateNewValue)은 삽입에 대한 사용자 트랜잭션이 활성화 되기 전에 (그리고 잠금이 수행되기 전에) 수행됩니다.

ID 값이 증가하고 할당 된 직후에 하나의 스레드를 고정 할 수 있도록 디버거와 함께 두 개의 삽입을 동시에 실행하면 시나리오를 재현 할 수있었습니다.

  1. 세션 1이 ID 값을 얻습니다 (3).
  2. 세션 2는 아이덴티티 값을 얻습니다 (4)
  3. 세션 2는 삽입 및 커밋을 수행합니다 (따라서 4 행이 완전히 표시됨)
  4. 세션 1은 삽입 및 커밋을 수행합니다 (행 3).

3 단계 후에 잠금 읽기 커밋에서 row_number 를 사용하는 쿼리 가 다음을 반환했습니다.

스크린 샷

구현시 Checkpoint ID 3이 잘못 건너 뜁니다.

기회의 창은 비교적 작지만 존재합니다. 디버거를 연결하는 것보다 더 현실적인 시나리오를 제공하려면 : 실행중인 쿼리 스레드는 위의 1 단계 이후에 스케줄러를 생성 할 수 있습니다. 이를 통해 두 번째 스레드가 원래 스레드가 삽입 수행을 재개하기 전에 ID 값을 삽입하고 커밋 할 수 있습니다.

명확성을 위해, ID 값이 할당 된 후 및 사용되기 전에 ID 값을 보호하는 잠금 또는 기타 동기화 오브젝트가 없습니다. 예를 들어, 위의 1 단계 이후에 동시 트랜잭션은 IDENT_CURRENT행이 테이블에 존재하기 전에 (커밋되지 않은) T-SQL 함수를 사용하여 새 ID 값을 볼 수 있습니다 .

기본적으로 문서화 된 것보다 더 이상 신원 가치에 대한 보장은 없습니다 .

  • 각각의 새로운 값은 현재 시드 및 증분에 따라 생성됩니다.
  • 특정 트랜잭션에 대한 각각의 새로운 값은 테이블의 다른 동시 트랜잭션과 다릅니다.

정말 그렇습니다.

경우 엄격한 트랜잭션 FIFO 처리가 필요합니다, 당신은 가능성이 선택의 여지가 있지만, 수동으로 직렬화 할 수 있습니다. 응용 프로그램에 하나의 요구 사항이 적 으면 더 많은 옵션이 있습니다. 그 점에서 문제는 100 % 명확하지 않습니다. 그럼에도 불구하고 Remus Rusanu의 기사 Using Tables as Queues 에서 유용한 정보를 찾을 수 있습니다 .


7

Paul White가 절대적으로 옳은 대답을했을 때 일시적으로 "건너 뛴"ID 행이있을 가능성이 있습니다. 다음은이 사례를 스스로 재현하는 작은 코드입니다.

데이터베이스와 테스트 테이블을 작성하십시오.

create database IdentityTest
go
use IdentityTest
go
create table dbo.IdentityTest (ID int identity, c1 char(10))
create clustered index CI_dbo_IdentityTest_ID on dbo.IdentityTest(ID)

C # 콘솔 프로그램에서이 테이블에서 동시 삽입 및 선택을 수행하십시오.

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading;

namespace IdentityTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var insertThreads = new List<Thread>();
            var selectThreads = new List<Thread>();

            //start threads for infinite inserts
            for (var i = 0; i < 100; i++)
            {
                insertThreads.Add(new Thread(InfiniteInsert));
                insertThreads[i].Start();
            }

            //start threads for infinite selects
            for (var i = 0; i < 10; i++)
            {
                selectThreads.Add(new Thread(InfiniteSelectAndCheck));
                selectThreads[i].Start();
            }
        }

        private static void InfiniteSelectAndCheck()
        {
            //infinite loop
            while (true)
            {
                //read top 2 IDs
                var cmd = new SqlCommand("select top(2) ID from dbo.IdentityTest order by ID desc")
                {
                    Connection = new SqlConnection("Server=localhost;Database=IdentityTest;Integrated Security=SSPI;Application Name=IdentityTest")
                };

                try
                {
                    cmd.Connection.Open();
                    var dr = cmd.ExecuteReader();

                    //read first row
                    dr.Read();
                    var row1 = int.Parse(dr["ID"].ToString());

                    //read second row
                    dr.Read();
                    var row2 = int.Parse(dr["ID"].ToString());

                    //write line if row1 and row are not consecutive
                    if (row1 - 1 != row2)
                    {
                        Console.WriteLine("row1=" + row1 + ", row2=" + row2);
                    }
                }
                finally
                {
                    cmd.Connection.Close();
                }
            }
        }

        private static void InfiniteInsert()
        {
            //infinite loop
            while (true)
            {
                var cmd = new SqlCommand("insert into dbo.IdentityTest (c1) values('a')")
                {
                    Connection = new SqlConnection("Server=localhost;Database=IdentityTest;Integrated Security=SSPI;Application Name=IdentityTest")
                };

                try
                {
                    cmd.Connection.Open();
                    cmd.ExecuteNonQuery();
                }
                finally
                {
                    cmd.Connection.Close();
                }
            }
        }
    }
}

이 콘솔은 읽기 스레드 중 하나가 항목을 "누락"할 때 모든 경우에 대한 행을 인쇄합니다.


1
좋은 코드이지만 연속 ID 만 검사합니다 ( "row1과 row가 연속적이지 않은 경우 // 쓰기 라인" ) 코드가 인쇄되는 간격이 생길 수 있습니다. 그렇다고 이러한 격차가 나중에 채워지는 것은 아닙니다.
ypercubeᵀᴹ

1
코드는 IDENTITY간격을 생성 하는 시나리오 (트랜잭션 롤백과 같은 시나리오)를 트리거하지 않기 때문에 인쇄 된 줄에는 실제로 "건너 뛴"값이 표시됩니다 (또는 적어도 내 컴퓨터에서 실행하고 확인할 때 수행 한 값). 아주 좋은 재현 샘플!
Fabian Schmied

5

간격을 남길 수있는 시나리오가 많기 때문에 ID가 연속적이지 않을 것을 권장합니다. 정체성을 추상적 인 숫자처럼 고려하고 비즈니스 의미를 부여하지 않는 것이 좋습니다.

기본적으로 INSERT 조작을 롤백하거나 명시 적으로 행을 삭제하면 공백이 발생할 수 있으며 테이블 특성 IDENTITY_INSERT를 ON으로 설정하면 복제가 발생할 수 있습니다.

다음과 같은 경우 간격이 발생할 수 있습니다.

  1. 레코드가 삭제됩니다.
  2. 새 레코드를 삽입하려고 할 때 오류가 발생했습니다 (롤백).
  3. 명시 적 값을 갖는 업데이트 / 삽입 (identity_insert 옵션).
  4. 증분 값이 1보다 큽니다.
  5. 트랜잭션이 롤백됩니다.

열의 ID 속성은 다음을 보장하지 않습니다.

• 독창성

• 거래 내에서 연속적인 가치. 값이 연속적이어야하는 경우 트랜잭션은 테이블에서 독점 잠금을 사용하거나 SERIALIZABLE 격리 레벨을 사용해야합니다.

• 서버를 다시 시작한 후의 연속 값.

• 값 재사용.

이로 인해 ID 값을 사용할 수없는 경우 현재 값을 보유하는 별도의 테이블을 작성하고 애플리케이션으로 테이블 및 번호 지정에 대한 액세스를 관리하십시오. 이것은 성능에 영향을 줄 가능성이 있습니다.

https://msdn.microsoft.com/en-us/library/ms186775(v=sql.105).aspx
https://msdn.microsoft.com/en-us/library/ms186775(v=sql.110) .aspx


나는 격차가 나의 주요한 문제가 아니라고 생각한다. 나의 주요 문제는 가치의 가시성을 높이는 것이다. (즉, 신원 값 7은 신원 값 6이 나오기 전에 해당 값을 기준으로하는 쿼리 순서를 관찰 할 수 없어야합니다.)
Fabian Schmied

1
1, 2, 5, 3, 4 : 나는 ID 값이 같은 커밋 보았다
stacylaray

물론 이것은 Lennart의 답변에서 나온 시나리오를 사용하여 쉽게 재현 할 수 있습니다. 내가 고투하고있는 질문 은 절 (클러스터형 인덱스의 순서)이 있는 쿼리를 사용할 때 커밋 순서를 관찰 할 수 있는지 여부 ORDER BY CheckpointSequence입니다. Identity 값의 생성이 INSERT 문에 의해 수행 된 잠금에 연결되어 있는지 아니면 SQL Server에 의해 수행 된 두 개의 관련없는 작업인지에 대한 질문으로 귀결됩니다.
Fabian Schmied 6

1
쿼리 란 무엇입니까? read commit을 사용하는 경우, 예를 들어 order by는 1, 2, 3, 5가 커밋되고 4가 읽히지 않았기 때문에 즉, 더티 읽기로 표시됩니다. 또한 NEventStore에 대한 설명은 "따라서 다시는 고려되지 않으므로 이벤트를 건너 뛸 수 없어야합니다."라고 말합니다.
stacylaray

쿼리는 위에 주어진다 ( gist.github.com/fschmied/47f716c32cb64b852f90)- 페이징되었지만 간단한 것으로 요약된다 SELECT ... FROM Commits WHERE CheckpointSequence > ... ORDER BY CheckpointSequence. 이 쿼리가 잠긴 행 4를지나 읽지 않을 것이라고 생각합니까? (내 실험에서 쿼리가 행 4에 대한 KEY 잠금을 획득하려고 할 때 차단됩니다.)
Fabian Schmied

1

때때로 서버에 과부하가 걸리면 문제가 발생하고 문제가 악화 될 수 있다고 생각합니다. 두 가지 트랜잭션을 고려하십시오.

  1. T1 : T에 삽입 ...- 5라고 삽입
  2. T2 : T에 삽입 ...-6이라고 삽입
  3. T2 : 커밋
  4. 독자는 6을 보지만 5는 보지 않습니다.
  5. T1 : 커밋

위의 시나리오에서 LAST_READ_ID는 6이므로 5는 읽지 않습니다.


테스트 결과 값이 5 인 행을 읽으려고 할 때 Reader (4 단계)가 T1이 잠금을 해제 할 때까지 차단하기 때문에이 시나리오는 문제가되지 않는 것으로 보입니다.
Fabian Schmied 6

당신은 옳을 수도 있습니다 .SQL 서버의 잠금 메커니즘을 잘 모르고 있습니다 (따라서 제 대답은 의심입니다).
Lennart

독자의 격리 수준에 따라 다릅니다. 그것은 둘 다 보거나, 막거나, 단지 6을 본다.
Michael Green

0

이 스크립트를 실행 :

BEGIN TRAN;
INSERT INTO dbo.Example DEFAULT VALUES;
COMMIT;

다음은 확장 이벤트 세션에서 캡처 한대로 획득 및 릴리스 한 잠금입니다.

name            timestamp                   associated_object_id    mode    object_id   resource_type   session_id  resource_description
lock_acquired   2016-03-29 06:37:28.9968693 1585440722              IX      1585440722  OBJECT          51          
lock_acquired   2016-03-29 06:37:28.9969268 7205759890195415040     IX      0           PAGE            51          1:1235
lock_acquired   2016-03-29 06:37:28.9969306 7205759890195415040     RI_NL   0           KEY             51          (ffffffffffff)
lock_acquired   2016-03-29 06:37:28.9969330 7205759890195415040     X       0           KEY             51          (29cf3326f583)
lock_released   2016-03-29 06:37:28.9969579 7205759890195415040     X       0           KEY             51          (29cf3326f583)
lock_released   2016-03-29 06:37:28.9969598 7205759890195415040     IX      0           PAGE            51          1:1235
lock_released   2016-03-29 06:37:28.9969607 1585440722              IX      1585440722  OBJECT          51      

작성중인 새 행에 대한 X 키 잠금 직전에 확보 한 RI_N KEY 잠금에 유의하십시오. 이 단기 범위 잠금은 RI_N 잠금이 호환되지 않기 때문에 동시 삽입이 다른 RI_N KEY 잠금을 획득하지 못하게합니다. 2 단계와 3 단계 사이에서 언급 한 창은 새로 생성 된 키의 행 잠금 이전에 범위 잠금이 획득되므로 문제가되지 않습니다.

언제 까지나 당신과 같이 SELECT...ORDER BY원하는 새로 삽입 된 행하기 전에 스캔을 시작, 난 당신이 기본에 원하는 동작을 기대할 수있는 READ COMMITTED데이터베이스만큼 격리 수준 READ_COMMITTED_SNAPSHOT옵션이 꺼져 있습니다.


1
technet.microsoft.com/en-us/library/… 에 따르면 , 두 개의 잠금 장치 RangeI_N호환됩니다 . 즉 서로를 차단하지 않습니다 (잠금은 기존 직렬화 가능 리더를 차단하기 위해 대부분 존재합니다).
Fabian Schmied

@FabianSchmied, 재미있는. 이 항목은 technet.microsoft.com/en-us/library/ms186396(v=sql.105).aspx 의 잠금 호환성 매트릭스와 충돌 하며 잠금이 호환되지 않음을 나타냅니다. 언급 한 링크의 삽입 예는 내 답변의 트레이스에 표시된 것과 동일한 동작을 나타냅니다 (전용 키 잠금 전에 범위를 테스트하기위한 수명이 짧은 삽입 범위 잠금).
Dan Guzman

1
실제로, 매트릭스는 "충돌 없음"( "호환되지 않음")에 대해 "N"이라고 표시합니다.
Fabian Schmied

0

SQL Server를 이해하면 기본 동작은 첫 번째 쿼리가 커밋 될 때까지 두 번째 쿼리가 결과를 표시하지 않는 것입니다. 첫 번째 쿼리가 COMMIT 대신 ROLLBACK을 수행하면 열에 누락 된 ID가 있습니다.

기본 구성

데이터베이스 테이블

다음 구조로 데이터베이스 테이블을 작성했습니다.

CREATE TABLE identity_rc_test (
    ID4VALUE INT IDENTITY (1,1), 
    TEXTVALUE NVARCHAR(20),
    CONSTRAINT PK_ID4_VALUE_CLUSTERED 
        PRIMARY KEY CLUSTERED (ID4VALUE, TEXTVALUE)
)

데이터베이스 격리 수준

다음 문장으로 데이터베이스의 격리 수준을 확인했습니다.

SELECT snapshot_isolation_state, 
       snapshot_isolation_state_desc, 
       is_read_committed_snapshot_on
FROM sys.databases WHERE NAME = 'mydatabase'

내 데이터베이스에 대해 다음 결과를 반환했습니다.

snapshot_isolation_state    snapshot_isolation_state_desc   is_read_committed_snapshot_on
0                           OFF                             0

SQL Server 2012의 데이터베이스에 대한 기본 설정입니다.

테스트 스크립트

표준 SQL Server SSMS 클라이언트 설정 및 표준 SQL Server 설정을 사용하여 다음 스크립트가 실행되었습니다.

클라이언트 연결 설정

클라이언트는 READ COMMITTEDSSMS의 쿼리 옵션에 따라 트랜잭션 격리 수준을 사용하도록 설정되었습니다 .

쿼리 1

SPID 57의 쿼리 창에서 다음 쿼리가 실행되었습니다.

SELECT * FROM dbo.identity_rc_test
BEGIN TRANSACTION [FIRST_QUERY]
INSERT INTO dbo.identity_rc_test (TEXTVALUE) VALUES ('Nine')
/* Commit is commented out to prevent the INSERT from being commited
--COMMIT TRANSACTION [FIRST_QUERY]
--ROLLBACK TRANSACTION [FIRST_QUERY]
*/

쿼리 2

SPID 58을 사용하여 쿼리 창에서 다음 쿼리가 실행되었습니다.

BEGIN TRANSACTION [SECOND_QUERY]
INSERT INTO dbo.identity_rc_test (TEXTVALUE) VALUES ('Ten')
COMMIT TRANSACTION [SECOND_QUERY]
SELECT * FROM dbo.identity_rc_test

쿼리가 완료되지 않고 eXclusive 잠금이 PAGE에서 해제되기를 기다리고 있습니다.

잠금을 결정하는 스크립트

이 스크립트는 두 트랜잭션에 대한 데이터베이스 오브젝트에서 발생하는 잠금을 표시합니다.

SELECT request_session_id, resource_type,
       resource_description, 
       resource_associated_entity_id,
       request_mode, request_status
FROM sys.dm_tran_locks
WHERE request_session_id IN (57, 58)

결과는 다음과 같습니다.

58  DATABASE                    0                   S   GRANT
57  DATABASE                    0                   S   GRANT
58  PAGE            1:79        72057594040549300   IS  GRANT
57  PAGE            1:79        72057594040549300   IX  GRANT
57  KEY         (a0aba7857f1b)  72057594040549300   X   GRANT
58  KEY         (a0aba7857f1b)  72057594040549300   S   WAIT
58  OBJECT                      245575913           IS  GRANT
57  OBJECT                      245575913           IX  GRANT

결과는 쿼리 창 1 (SPID 57)에 DATABASE의 공유 잠금 (S)이 OBJECT의 IX (확장 확장) 잠금, 삽입하려는 PAGE의 IX (확장 확장) 잠금 및 확장이 있음을 보여줍니다. KEY의 잠금 (X)이 삽입되었지만 아직 커밋되지 않았습니다.

커밋되지 않은 데이터로 인해 두 번째 쿼리 (SPID 58)에는 DATABASE 수준의 공유 잠금 (S), OBJECT의 의도 된 공유 (IS) 잠금, 페이지의 의도 된 공유 (IS) 잠금이 있습니다 (S) ) 요청 상태가 WAIT 인 키를 잠급니다.

개요

첫 번째 쿼리 창의 쿼리는 커밋하지 않고 실행됩니다. 두 번째 쿼리는 READ COMMITTED데이터 만 가능하기 때문에 시간 초과가 발생하거나 첫 번째 쿼리에서 트랜잭션이 커밋 될 때까지 기다립니다.

이것은 Microsoft SQL Server의 기본 동작을 이해 한 것입니다.

첫 번째 명령문이 COMMIT되면 ID 문이 SELECT 문에 의한 후속 읽기를 위해 실제로 순서대로 있음을 관찰해야합니다.

첫 번째 명령문이 ROLLBACK을 수행하는 경우 시퀀스에서 누락 된 ID를 찾을 수 있지만 ID가 오름차순으로 정렬됩니다 (ID 열에서 기본값 또는 ASC 옵션을 사용하여 INDEX를 작성한 경우).

최신 정보:

예, 문제가 발생할 때까지 ID 열이 올바르게 작동 할 수 있습니다. SQL Server 2000과 Microsoft 웹 사이트 의 ID 열에 관한 HOTFIX 는 하나뿐입니다 .

ID 열이 올바르게 업데이트되지 않으면 Microsoft 웹 사이트에 더 많은 핫픽스 또는 패치가 있다고 생각합니다.

Microsoft 지원 계약이있는 경우 언제든지 자문 사례를 열고 추가 정보를 요청할 수 있습니다.


1
분석해 주셔서 감사하지만 내 질문은 다음 Identity값 생성 과 행의 KEY 잠금 획득 (동시 읽기 / 쓰기가 발생할 수 있음) 사이에 시간 창이 있는지 여부 입니다. 나는 이것이 매우 짧은 시간 동안 쿼리 실행을 중지하고 잠금을 분석 할 수 없기 때문에 관찰에 의해 이것이 불가능하다고 생각하지 않습니다.
Fabian Schmied

당신은 그 진술을 멈출 수는 없지만, 나의 (느린) 관찰은 빠른 / 정상적으로 일어나는 것입니다. 한 SPID가 데이터를 삽입하기 위해 잠금을 획득하면 다른 SPID는 동일한 잠금을 획득 할 수 없습니다. 더 빠른 명령문은 이미 잠금과 ID를 순서대로 획득 한 이점이 있습니다. 다음 명령문은 잠금이 해제 된 후 다음 ID를 수신합니다.
John aka hot2use 2016 년

1
일반적으로, 당신의 관찰은 나의 것과 (그리고 나의 기대와도) 일치합니다. 그래도 유지되지 않는 예외적 인 상황이 있는지 궁금합니다.
Fabian Schmied 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.