ИЗМЕНИТЬ
@Remus исправил мой тестовый образец. Вы можете увидеть исправленную версию в его ответе ниже.
Я принял предложение заменить INT на DECIMAL(29,0) и получил следующие результаты:
Десятичный: 2133
GUID: 1836
Случайные вставки по-прежнему выигрывают, даже если ряд немного больше.
Несмотря на объяснения, указывающие на то, что случайные вставки медленнее, чем последовательные, эти тесты показывают, что они явно быстрее. Объяснения, которые я получаю, не согласуются с тестами. Поэтому мой вопрос по-прежнему сосредоточен на b-деревьях, последовательных вставках и скорости.
...
Я знаю по опыту, что b-деревья имеют ужасную производительность, когда данные добавляются к ним последовательно (независимо от направления). Однако когда данные добавляются случайным образом, достигается наилучшая производительность.
Это легко продемонстрировать с помощью RB-Tree. При последовательной записи выполняется максимальное количество балансировок дерева.
Я знаю, что очень немногие базы данных используют бинарные деревья, а используют сбалансированные деревья n-го порядка. Я логически предполагаю, что их ждет та же участь, что и бинарные деревья, когда речь идет о последовательном вводе.
Это разожгло мое любопытство.
Если это так, то можно сделать вывод, что запись последовательных идентификаторов (например, в IDENTITY(1,1)) приведет к многократной перебалансировке дерева. Я видел многие сообщения, выступающие против GUID, поскольку "это вызовет случайную запись". Я никогда не использую GUID, но меня поразило, что это "плохое" замечание на самом деле было хорошим замечанием.
Поэтому я решил проверить это. Вот мой код:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[T1](
[ID] [int] NOT NULL
CONSTRAINT [T1_1] PRIMARY KEY CLUSTERED ([ID] ASC)
)
GO
CREATE TABLE [dbo].[T2](
[ID] [uniqueidentifier] NOT NULL
CONSTRAINT [T2_1] PRIMARY KEY CLUSTERED ([ID] ASC)
)
GO
declare @i int, @t1 datetime, @t2 datetime, @t3 datetime, @c char(300)
set @t1 = GETDATE()
set @i = 1
while @i < 2000 begin
insert into T2 values (NEWID(), @c)
set @i = @i + 1
end
set @t2 = GETDATE()
WAITFOR delay '0:0:10'
set @t3 = GETDATE()
set @i = 1
while @i < 2000 begin
insert into T1 values (@i, @c)
set @i = @i + 1
end
select DATEDIFF(ms, @t1, @t2) AS [Int], DATEDIFF(ms, @t3, getdate()) AS [GUID]
drop table T1
drop table T2
Обратите внимание, что я не вычитаю время на создание GUID ни на значительно больший размер строки. Результаты на моей машине были следующими:
Целое: 17 340 мс GUID: 6 746 мс
Это означает, что в этом тесте случайные вставки 16 байтов были почти в 3 раза быстрее, чем последовательные вставки 4 байтов.
Кто-нибудь хочет это прокомментировать?
Пс. Я понимаю, что это не вопрос. Это приглашение к обсуждению, и это имеет отношение к изучению оптимального программирования.