Denaliシーケンスは、ID列よりもパフォーマンスが高いと想定されるのはなぜですか?


36

どちらが優れているに対する彼の答え:ID列または生成された一意のID値?mrdennyのコメント:

SQL Denaliが登場すると、IDよりも効率的なシーケンスがサポートされますが、より効率的なものを作成することはできません。

私はちょっと確信が持てません。Oracleのシーケンスを知っているので、挿入のトリガーを作成するか、各挿入をストアドプロシージャの呼び出しにカプセル化するか、アドホック挿入を行うときにシーケンスを適切に使用することを忘れないでください。

シーケンスの利点はそれほど明白ではないと思います。


2
私はそれがあなたの質問に答えないことを知っていますが、パフォーマンスの違いは別として、シーケンスには他の利点があります。たとえば、シーケンスはターゲット列の更新を停止しません。これはIDENTITYの非常に不便な制限です。
nvogel

回答:


37

ここでも答えます。それは、方法IDENTITYSEQUENCE作業の内部に関係しています。

を使用するとIDENTITY、SQL Serverは値をメモリに事前キャッシュして、すぐに使用できるようにします。詳細については、Martin Smithの回答を参照してください。値が使用されると、バックグラウンドプロセスにより多くの値が生成されます。ご想像のとおり、このプールはすぐに使い果たされる可能性があり、アプリケーションは値を生成しているバックグラウンドプロセスに左右されます。

ではSEQUENCE、SQL Serverは、キャッシュがどうあるべきか、大きな定義することができます。SQL Serverは実際に値をキャッシュに保持しませんが、現在の値と上限値のみを保持します。これにより、値の作成に必要なIOの量が大幅に削減されます。

キャッシュをあまり高く設定しないでください。これにより、使用できる数値の数が減ります。SQLServerがクラッシュした場合、現在のキャッシュ範囲で指定された使用されなかった値は失われます。

行の挿入については、次のように列のデフォルト値を指定するだけです。

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つのテストにすぎません。さまざまなバッチサイズの挿入でキャッシュサイズ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が以前のものであるかどうかは関係ありません。したがって、SQL ServerはすべてのIDキャッシュ関連のディスク書き込み。ただし、Sequence の場合、値はデータベースの外部を含むあらゆる目的に使用される可能性があるため、これ強制されます。したがって、100万の挿入と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.