Задав этот вопрос, сравнивая последовательные и непоследовательные GUID, я попытался сравнить производительность INSERT на 1) таблице с первичным ключом GUID, инициализируемой последовательно с newsequentialid()
, и 2) таблице с первичным ключом INT, инициализированной последовательно с identity(1,1)
. Я ожидал бы, что последний будет самым быстрым из-за меньшей ширины целых чисел, и также кажется более простым генерировать последовательное целое число, чем последовательный GUID. Но, к моему удивлению, INSERT в таблице с целочисленным ключом были значительно медленнее, чем в последовательной таблице GUID.
Это показывает среднее время использования (мс) для тестовых прогонов:
NEWSEQUENTIALID() 1977
IDENTITY() 2223
Кто-нибудь может объяснить это?
Был использован следующий эксперимент:
SET NOCOUNT ON
CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestInt (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
DBCC showcontig ('TestGuid2') WITH tableresults
DBCC showcontig ('TestInt') WITH tableresults
SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWSEQUENTIALID()]
FROM TestGuid2
GROUP BY batchNumber
SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [IDENTITY()]
FROM TestInt
GROUP BY batchNumber
DROP TABLE TestGuid2
DROP TABLE TestInt
ОБНОВЛЕНИЕ: модифицируя скрипт для выполнения вставок на основе таблицы TEMP, как в примерах Фила Сэндлера, Митча Уитта и Мартина ниже, я также обнаружил, что IDENTITY быстрее, чем должно быть. Но это не обычный способ вставки строк, и я до сих пор не понимаю, почему эксперимент поначалу не удался: даже если я опускаю GETDATE () из моего исходного примера, IDENTITY () все еще намного медленнее. Таким образом, кажется, что единственный способ сделать IDENTITY () превосходящим NEWSEQUENTIALID () - это подготовить строки для вставки во временную таблицу и выполнить множество вставок в виде пакетной вставки с использованием этой временной таблицы. В общем, я не думаю, что мы нашли объяснение этому феномену, а IDENTITY () все еще медленнее для большинства практических применений. Кто-нибудь может объяснить это?
INT IDENTITY
IDENTITY
не требует блокировки таблицы. Концептуально я мог видеть, что вы могли бы ожидать, что он принимает MAX (id) + 1, но в действительности следующее значение сохраняется. На самом деле это должно быть быстрее, чем найти следующий GUID.