¿Por qué se supone que las secuencias de Denali a funcionar mejor que las columnas de identidad?

dba.stackexchange https://dba.stackexchange.com/questions/1635

Pregunta

En su respuesta a ¿Qué es mejor :? columnas de identidad o valores únicos ID generado mrdenny dice:

Cuando SQL Denali sale apoyará secuencias que serán más eficientes que los de identidad, pero no se puede crear algo más eficiente a sí mismo.

No estoy tan seguro. Conociendo a Oracle de secuencias , tengo ya sea para crear un disparador para la inserción, encapsular cada inserto en una llamada de un procedimiento almacenado, o rezar que no se olvide de utilizar correctamente la secuencia cuando hago un ad- hoc inserto.

I cabe duda de que las ventajas de secuencias son tan evidentes.

¿Fue útil?

Solución

Voy a responder aquí también. Tiene que ver con el funcionamiento interno de la forma IDENTITY y SEQUENCE trabajo.

Con IDENTITY, SQL Server almacena en caché los valores pre-en la memoria de manera que sean fácilmente disponibles. Ver de Martin Smith respuesta para los detalles. Como se utilizan valores, un proceso en segundo plano genera más valores. Como se puede imaginar este grupo puede correr bastante rápidamente, dejando la aplicación a merced del proceso en segundo plano que está generando los valores.

Con SEQUENCE, SQL Server le permite definir qué tan grande debe ser la memoria caché. Aunque SQL Server en realidad no mantener los valores en la memoria caché, sólo se mantiene el valor actual y el valor extremo superior, esto reducirá en gran medida la cantidad de IO que se necesita para crear valores.

No establezca la caché demasiado alto, ya que esto reducirá la cantidad de números que se pueden utilizar:. Si SQL Server fuera a chocar, los valores especificados en el rango de caché actual no utilizados se perderían

En cuanto a la inserción fila, basta con especificar un valor predeterminado para la columna, así:

DEFAULT (NEXT VALUE FOR Audit.EventCounter),

Otros consejos

el artículo Itzik Ben Gan fue escrito el tamaño de caché hardcoded de 10 para IDENTITY parece haber sido cambiado. De los comentarios de esta elemento de conexión

El tamaño de la pre-asignación se basa en el tamaño del tipo de datos de la columna de la propiedad de identidad se define en. Para un servidor SQL Server columna número entero, el servidor de pre-Asigna identidades en las gamas de 1000 valores. Para los datos BIGINT escriba los servidores pre-asigna en rangos de 10000 valores.

T-SQL Consulta contiene la siguiente tabla, pero enfatiza que estos valores no están documentados o garantiza que sea sin cambios.

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

El artículo aquí pruebas varios caché secuencia tamaños y tamaños de lote y viene con los siguientes resultados.

introducir descripción de la imagen aquí

Lo que parece demostrar que para las grandes inserciones IDENTITY fuera realiza SEQUENCE. No prueba tamaño de caché de 1000, sin embargo, y también esos resultados son sólo una prueba. Mirando específicamente a tamaño de caché 1000 con diversos tamaños de lote de insertos Me dieron los siguientes resultados (tratando cada tamaño de lote de 50 veces y la agregación de los resultados como a continuación- todo momento en mu 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 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+

Para mayor tamaño de lote de la versión IDENTITY parece general rápido .

El libro de TSQL Consulta también explica por qué IDENTITY puede tener una ventaja de rendimiento sobre la secuencia.

El IDENTITY es específico mesa y SEQUENCE no lo es. Si era un desastre de huelga a mediados de inserción antes de que se tiraba el búfer de registro que no importa si el recuperado la identidad es una anterior ya que el proceso de recuperación también deshará el inserto, por lo que SQL Server no forzar vaciar el búfer de registro en toda identidad caché de escritura de disco relacionada. Sin embargo, para esta secuencia es forzada como el valor podría ser utilizado para cualquier propósito - incluso fuera de la base de datos. Así en el ejemplo anterior con un millón de insertos y tamaño de caché de 1000 esto es un adicional de mil vaciados de registro.

Script para reproducir

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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a dba.stackexchange
scroll top