С тех пор, как была написана статья Ицик Бен Ган, жестко закодированный размер кэша 10, IDENTITY
похоже, изменился. Из комментариев к этому элементу подключения
Размер предварительного выделения основан на размере типа данных столбца, для которого определено свойство идентификатора. Для целочисленного столбца SQL Server сервер предварительно выделяет идентификаторы в диапазонах 1000 значений. Для типа данных bigint сервер предварительно выделяет в диапазоне 10000 значений.
Книга запросов T-SQL содержит следующую таблицу, но подчеркивает, что эти значения не документированы и не гарантируются неизменными.
+-----------------+-----------+
| DataType | CacheSize |
+-----------------+-----------+
| TinyInt | 10 |
| SmallInt | 100 |
| Int | 1,000 |
| BigInt, Numeric | 10,000 |
+-----------------+-----------+
В этой статье мы проверяем различные размеры кэша последовательностей и размеры пакетов вставок и приводим следующие результаты.
Который, кажется, показывает, что для больших вставок IDENTITY
выполняет SEQUENCE
. Тем не менее, он не проверяет размер кеша 1000, и эти результаты - только один тест. Рассматривая конкретно размер кэша 1000 с различными размерами пакетов вставок, я получил следующие результаты (пробуя каждый размер пакета 50 раз и агрегируя результаты как показано ниже - все разы в мкс).
+------------+-----------+-----------+-----------+-----------+-----------+-----------+
| | 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
не является. Если произошла авария в середине вставки до того, как буфер журнала был сброшен, не имеет значения, является ли восстановленная идентификация более ранней, поскольку процесс восстановления также отменяет вставку, поэтому SQL Server не принудительно сбрасывает буфер журнала при каждой идентификации запись диска на кеш. Однако для последовательности это будет исполнено , поскольку значение может быть использовано для любых целей - в том числе и за пределами базы данных. Таким образом, в приведенном выше примере с миллионом вставок и размером кэша в 1000 это дополнительные тысячи сбросов журнала.
Скрипт для воспроизведения
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;