Задавши це питання, порівнюючи послідовні та непослідовні GUID, я спробував порівняти продуктивність INSERT на 1) таблиці з первинним ключем GUID, ініціалізованою послідовно newsequentialid()
, та 2) таблиці з первинним ключем INT, ініціалізованим послідовно identity(1,1)
. Я б очікував, що остання буде найшвидшою через меншу ширину цілих чисел, а також видається простішим для отримання послідовного цілого числа, ніж послідовного GUID. Але на мій подив, ВСТАВКИ на столі з цілим ключем були значно повільнішими, ніж послідовна таблиця 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, як у прикладах Філа Сандлера, Мітча Пшениці та Мартіна нижче, я також вважаю, що ІДЕНТИЧНІСТЬ швидша, як і повинна бути. Але це не звичайний спосіб вставлення рядків, і я досі не розумію, чому експеримент спочатку пішов не так: навіть якщо я опускаю GETDATE () з мого оригінального прикладу, IDENTITY () все ще відбувається повільніше. Отже, здається, що єдиний спосіб перемогти IDENTITY () перевершити NEWSEQUENTIALID () - це підготувати рядки до вставки у тимчасовій таблиці та виконати безліч вставок як пакетної вставки за допомогою цієї таблиці temp. Загалом, я не думаю, що ми знайшли пояснення цьому явищу, і IDENTITY () все ще здається повільнішим для більшості практичних звичаїв. Хтось може це пояснити?
IDENTITY
не потрібно блокування таблиці. Концептуально я міг бачити, що ви можете очікувати, що він буде приймати MAX (id) + 1, але насправді наступне значення зберігається. Насправді це має бути швидше, ніж пошук наступного GUID.