Denali 시퀀스가 ​​ID 열보다 성능이 더 좋은 이유는 무엇입니까?


36

자신의 답변에서 어느 것이 더 낫습니까? 아이덴티티 열 또는 생성 된 고유 ID 값? mrdenny는 말한다 :

SQL Denali가 나오면 ID보다 효율적인 시퀀스를 지원하지만 더 효율적인 무언가를 만들 수는 없습니다.

확실하지 않아요. Oracle의 시퀀스를 알고 있으면 삽입을위한 트리거를 작성하거나 각 삽입을 스토어드 프로 시저 호출로 캡슐화하거나 임시 삽입을 수행 할 때 순서를 올바르게 사용하는 것을 잊지 않도록기도해야합니다.

시퀀스의 장점이 너무 분명하다는 것을 의심합니다.


2
귀하의 질문에 대답하지 않지만 성능 차이를 제외하고는 시퀀스에 다른 이점이 있습니다. 예를 들어 시퀀스는 대상 열 업데이트를 중지하지 않습니다. 이는 IDENTITY의 매우 불편한 제한입니다.
nvogel

답변:


37

여기에도 대답하겠습니다. 그것은 방법 IDENTITYSEQUENCE작업 의 내부 와 관련이 있습니다.

을 사용 IDENTITY하면 SQL Server는 값을 메모리에 미리 캐시하여 쉽게 사용할 수 있습니다. 자세한 내용은 Martin Smith의 답변 을 참조하십시오. 값이 사용되면 백그라운드 프로세스에서 더 많은 값을 생성합니다. 당신이 상상할 수 있듯이이 풀은 꽤 빨리 실행될 수 있으며 응용 프로그램은 값을 생성하는 백그라운드 프로세스의 자비에 맡겨집니다.

을 사용 SEQUENCE하면 SQL Server에서 캐시 크기를 정의 할 수 있습니다. SQL Server는 실제로 캐시에 값을 유지하지 않지만 현재 값과 최상위 값만 유지하므로 값을 만드는 데 필요한 IO의 양이 크게 줄어 듭니다.

캐시를 너무 높게 설정하지 않으면 사용할 수있는 수가 줄어 듭니다. SQL Server가 충돌하면 사용되지 않은 현재 캐시 범위에 지정된 값이 손실됩니다.

행 삽입의 경우 다음과 같이 열의 기본값을 지정하십시오.

DEFAULT (NEXT VALUE FOR Audit.EventCounter),

21

Itzik Ben Gan 기사 가 작성된 이래로 하드 코딩 된 캐시 크기 10은 IDENTITY변경된 것으로 보입니다. 에서 이 연결 항목에 대한 의견

사전 할당의 크기는 ID 속성이 정의 된 열의 데이터 형식 크기를 기반으로합니다. SQL Server 정수 열의 경우 서버는 1000 개의 값 범위로 ID를 미리 할당합니다. bigint 데이터 유형의 경우 서버는 10000 값 범위로 미리 할당됩니다.

T-SQL 쿼리의 책은 다음 표를 포함하지만,이 값은 문서화 또는 변경되지 보장되지 않습니다 것을 강조한다.

+-----------------+-----------+
|    DataType     | CacheSize |
+-----------------+-----------+
| TinyInt         | 10        |
| SmallInt        | 100       |
| Int             | 1,000     |
| BigInt, Numeric | 10,000    |
+-----------------+-----------+

이 기사에서는 다양한 시퀀스 캐시 크기와 삽입 배치 크기를 테스트하고 다음과 같은 결과를 얻습니다.

여기에 이미지 설명을 입력하십시오

큰 인서트의 경우 IDENTITY성능이 우수함을 보여주는 것으로 보입니다 SEQUENCE. 그러나 캐시 크기 1,000은 테스트하지 않으며 결과는 하나의 테스트입니다. 다양한 배치 크기의 인서트가있는 캐시 크기 1,000을 구체적으로 살펴보면 다음과 같은 결과를 얻었습니다 (각 배치 크기를 50 회 시도하고 결과를 아래의 모든 시간을 μs로 집계).

+------------+-----------+-----------+-----------+-----------+-----------+-----------+
|            |             Sequence              |             Identity              |
| Batch Size |    Min    |    Max    |    Avg    |    Min    |    Max    |    Avg    |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
| 10         | 2,994     | 7,004     | 4,002     | 3,001     | 7,005     | 4,022     |
| 100        | 3,997     | 5,005     | 4,218     | 4,001     | 5,010     | 4,238     |
| 1,000      | 6,001     | 19,013    | 7,221     | 5,982     | 8,006     | 6,709     |
| 10,000     | 26,999    | 33,022    | 28,645    | 24,015    | 34,022    | 26,114    |
| 100,000    | 189,126   | 293,340   | 205,968   | 165,109   | 234,156   | 173,391   |
| 1,000,000  | 2,208,952 | 2,344,689 | 2,269,297 | 2,058,377 | 2,191,465 | 2,098,552 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+

더 큰 배치 크기의 경우 IDENTITY버전이 일반적으로 더 빠릅니다 .

TSQL 쿼리 책은 IDENTITY시퀀스보다 성능 이점이있는 이유도 설명합니다 .

IDENTITY테이블의 특정와 SEQUENCE없습니다. 로그 버퍼를 플러시하기 전에 재해가 삽입 중반에 닥친 경우 복구 프로세스가 삽입을 취소하기 때문에 복구 된 ID가 이전 ID인지 여부는 중요하지 않으므로 SQL Server는 모든 ID에서 로그 버퍼를 강제로 플러시하지 않습니다. 캐시 관련 디스크 쓰기. 그러나 순서이가 되어 데이터베이스 외부를 포함하여 - 값이 목적을 위해 이용 될 수있는대로 시행. 따라서 위의 예에서 삽입 횟수가 백만이고 캐시 크기가 1,000 인 경우 이는 1,000 회의 로그 플러시입니다.

재현 할 스크립트

DECLARE @Results TABLE(
  BatchCounter INT,
  NumRows      INT,
  SequenceTime BIGINT,
  IdTime       BIGINT);

DECLARE @NumRows      INT = 10,
        @BatchCounter INT;

WHILE @NumRows <= 1000000
  BEGIN
      SET @BatchCounter = 0;

      WHILE @BatchCounter <= 50
        BEGIN
            --Do inserts using Sequence
            DECLARE @SequenceTimeStart DATETIME2(7) = SYSUTCDATETIME();

            INSERT INTO dbo.t1_Seq1_cache_1000
                        (c1)
            SELECT N
            FROM   [dbo].[TallyTable] (@NumRows)
            OPTION (RECOMPILE);

            DECLARE @SequenceTimeEnd DATETIME2(7) = SYSUTCDATETIME();
            --Do inserts using IDENTITY
            DECLARE @IdTimeStart DATETIME2(7) = SYSUTCDATETIME();

            INSERT INTO dbo.t1_identity
                        (c1)
            SELECT N
            FROM   [dbo].[TallyTable] (@NumRows)
            OPTION (RECOMPILE);

            DECLARE @IdTimeEnd DATETIME2(7) = SYSUTCDATETIME();

            INSERT INTO @Results
            SELECT @BatchCounter,
                   @NumRows,
                   DATEDIFF(MICROSECOND, @SequenceTimeStart, @SequenceTimeEnd) AS SequenceTime,
                   DATEDIFF(MICROSECOND, @IdTimeStart, @IdTimeEnd)             AS IdTime;

            TRUNCATE TABLE dbo.t1_identity;

            TRUNCATE TABLE dbo.t1_Seq1_cache_1000;

            SET @BatchCounter +=1;
        END

      SET @NumRows *= 10;
  END

SELECT NumRows,
       MIN(SequenceTime) AS MinSequenceTime,
       MAX(SequenceTime) AS MaxSequenceTime,
       AVG(SequenceTime) AS AvgSequenceTime,
       MIN(IdTime)       AS MinIdentityTime,
       MAX(IdTime)       AS MaxIdentityTime,
       AVG(IdTime)       AS AvgIdentityTime
FROM   @Results
GROUP  BY NumRows;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.