Кластерный столбец GUID и newsequentialid на разных серверах

Хорошо известно, что использование случайных значений в столбце с кластеризованным индексом не является хорошей идеей, поэтому использование GUID для первичного ключа с кластеризованным индексом обычно не рекомендуется. Используя функцию newsequentialid(), мы можем преодолеть большинство из этих трудностей.

Однако что произойдет, если вы генерируете GUID на ферме веб-серверов, все из которых попадают в одну базу данных? Я создаю последовательные идентификаторы в коде.NET, используя UuidCreateSequential, как описано в этой статье: http://blogs.msdn.com/b/dbrowne/archive/2012/07/03/how-to-generate-sequential-guids-for-sql-server-in-net.aspx

Проблема заключается в том, что, хотя полученные идентификаторы GUID являются последовательными с одного компьютера, это не относится к нескольким компьютерам. Поскольку наиболее значимые 11 байтов (в соответствии с SQL Server), по-видимому, остаются практически одинаковыми для одной и той же машины, он эффективно сортирует по машине, а затем по времени, а не по желаемой противоположности.

Было бы целесообразным и выполнимым изменить порядок байтов в GUID для получения почти последовательных идентификаторов GUID между компьютерами, или я должен отказаться и сделать индексы некластерными?

Спасибо!

2 ответа

Решение

После этого я собираюсь ответить на свой вопрос и сказать, что генерация последовательных идентификаторов GUID (COMB GUID) из нескольких машин, как описано в вопросе, не является проблемой. По сути, у вас будет одна отдельная последовательность идентификаторов для каждого компьютера, что не приведет к разбиению страниц, поскольку они будут добавляться в конец разных страниц, а не в середину страницы (поскольку новый идентификатор всегда будет самым большим в своей последовательности).

Хотя GUID может быть не таким эффективным, как int, у меня не было проблем с использованием этого подхода с миллионами строк в таблице.

Вы также можете сгенерировать свои идентификаторы на C#, взгляните на это сообщение о проекте кода. prb в том, что код, сгенерированный этой реализацией, не совпадает с тем, что генерирует NEWSEQUENTIALID, так как моя цель состояла в том, чтобы код C# генерировал последние 6 байтов Guid как функции NewSequentialID сервера Sql, я получаю следующий код.

public static Guid ToSequentialAtEnd(this Guid guid)
{
    byte[] guidArray = guid.ToByteArray();

    DateTime now = DateTime.UtcNow;
    var baseDate = new DateTime(1900, 1, 1);

    // Get the days and milliseconds which will be used to build the byte string 
    var days = new TimeSpan(now.Ticks - baseDate.Ticks);
    TimeSpan msecs = now.TimeOfDay;

    // Convert to a byte array 
    // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.33333333 
    byte[] daysArray = BitConverter.GetBytes(days.Days);
    byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds / 3.33333333));

    // Reverse the bytes to match SQL Servers ordering 
    Array.Reverse(daysArray);
    Array.Reverse(msecsArray);

    // Copy the bytes into the guid 
    Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
    Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);

    return new Guid(guidArray);
}
Другие вопросы по тегам