Я недавно унаследовал базу данных SQL Server, которая использует BINARY(16)
вместо UNIQUEIDENTIFIER
хранения Guids. Это делает это для всего, включая первичные ключи.
Должен ли я быть обеспокоен?
sql-server
migration
uuid
Джонатан Аллен
источник
источник
Ответы:
Ну, есть пара вещей, которые немного касаются.
Первое: хотя верно, что
UNIQUEIDENTIFIER
(то естьGuid
) является 16-байтовым двоичным значением, также верно, что:INT
могут быть сохраненыBINARY(4)
,DATETIME
могут быть сохранены вBINARY(8)
и т. Д.), Следовательно, # 2 ↴sysname
в качестве псевдонима дляNVARCHAR(128)
).Три поведенческих различия, которые я могу найти:
Сравнение
UNIQUEIDENTIFIER
значений в SQL Server, к лучшему или к худшему, фактически не выполняется так же, как сравнениеBINARY(16)
значений. Согласно странице MSDN для сравнения значений GUID и уникального идентификатора , при сравненииUNIQUEIDENTIFIER
значений в SQL Server:Хотя эти значения сортируются не часто, между этими двумя типами есть небольшая разница. Согласно странице MSDN для уникального идентификатора :
Учитывая, что существуют различия в том, как обрабатываются значения GUID между SQL Server и .NET (отмечено на странице «Сравнение значений GUID и уникальных идентификаторов», ссылка на которую приведена выше), извлечение этих данных из SQL Server в код приложения может быть неправильно обработано в код приложения, если необходимо эмулировать поведение сравнения SQL Server. Такое поведение можно эмулировать, конвертируя в a
SqlGuid
, но знает ли разработчик, что делать это?Второе: на основании следующего утверждения
В целом, я бы беспокоился о производительности системы, используя GUID в качестве PK вместо альтернативных ключей вместе с использованием
INT
или дажеBIGINT
в качестве PK. И даже больше беспокоит, являются ли эти GUID PK кластерными индексами.ОБНОВИТЬ
Следующий комментарий, сделанный ФП к ответу @ Роба, вызывает дополнительную озабоченность:
GUID могут храниться в 2 разных двоичных форматах . Таким образом, может быть причина для беспокойства в зависимости от:
Проблема с тем, где было сгенерировано двоичное представление, связана с порядком байтов первых 3 из 4 «полей». Если вы перейдете по ссылке выше на статью в Википедии, вы увидите, что RFC 4122 указывает на использование кодировки «Big Endian» для всех 4 полей, а идентификаторы Microsoft GUID указывают на использование «Собственного» Endianness. Итак, архитектура Intel имеет формат Little Endian, следовательно, порядок следования байтов для первых 3 полей меняется в зависимости от RFC (а также GUID в стиле Microsoft, генерируемых в системах Big Endian). Первое поле, «Данные 1», составляет 4 байта. В одном Endianness это будет представлено как (гипотетически)
0x01020304
. Но в другом Endianness это было бы0x04030201
. Так что, если текущая база данныхBINARY(16)
это двоичное представление было сгенерировано в системе, следующей за RFC, и преобразование данных, находящихся в настоящее время вBINARY(16)
поле, вUNIQUEIDENTIFIER
результат приведет к тому, что GUID будет отличаться от того, который был изначально создан. Это на самом деле не создает проблемы, если значения никогда не покидают базу данных, а значения сравниваются только на равенство, а не на порядок.Проблема с порядком заключается в том, что они не будут в том же порядке после преобразования в
UNIQUEIDENTIFIER
. К счастью, если исходная система действительно была MySQL, то в двоичном представлении упорядочение никогда не выполнялось, так как MySQL имеет только строковое представление UUID .Опасность использования строковых значений вне базы данных более серьезна, опять же, если двоичное представление было создано вне Windows / SQL Server. Поскольку порядок байтов потенциально различен, один и тот же GUID в строковой форме приведет к 2 различным двоичным представлениям, в зависимости от того, где произошло это преобразование. Если код приложения или клиенты получили GUID в виде строки как
ABC
исходящий из двоичной формы123
и двоичное представление было сгенерировано в системе, следующей за RFC, то это же двоичное представление (то есть123
) будет преобразовано в строковую формуDEF
при преобразовании в аUNIQUEIDENTIFIER
. Аналогично, исходная строковая формаABC
преобразуется в двоичную форму456
при преобразовании вUNIQUEIDENTIFIER
.Таким образом, если GUID никогда не покидали базу данных, не о чем беспокоиться за пределами порядка. Или, если импорт из MySQL был сделан путем преобразования строковой формы (то есть
FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
), тогда это могло бы быть хорошо. Иначе, если эти GUID были предоставлены клиентам или в коде приложения, вы можете проверить, как они конвертируют, получив его и выполнив конвертацию,SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
и посмотреть, найдена ли ожидаемая запись. Если вы не можете сопоставить записи, возможно, вам придется оставить поля какBINARY(16)
.По всей вероятности, проблем не будет, но я упоминаю об этом, потому что при правильных условиях может возникнуть проблема.
И как новые GUID вставляются в любом случае? Генерируется в коде приложения?
ОБНОВЛЕНИЕ 2
Если предыдущее объяснение потенциальной проблемы, связанной с импортом двоичных представлений GUID, сгенерированных в другой системе, немного (или много) сбивало с толку, надеюсь, следующее будет немного яснее:
В выводе, показанном выше, значения «String» и «Binary» относятся к одному и тому же GUID. Значение под строкой «Binary» совпадает со значением строки «Binary», но отформатировано в том же стиле, что и строка «String» (т. Е. Удалено «0x» и добавлено четыре черты). Сравнивая первое и третье значения, они не совсем одинаковы, но они очень близки: самые правые два раздела идентичны, а самые левые три раздела - нет. Но если вы присмотритесь, вы увидите, что это одинаковые байты в каждом из трех разделов, просто в другом порядке. Возможно, будет проще увидеть, покажу ли я только эти первые три раздела и нумерую байты, чтобы было легче увидеть, как их порядок отличается между двумя представлениями:
Строка = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binary = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (в Windows / SQL Server)
Таким образом, в каждой группе порядок следования байтов меняется, но только в Windows, а также в SQL Server. Однако в системе, которая придерживается RFC, двоичное представление будет зеркально отображать строковое представление, потому что не будет никакого изменения порядка байтов.
Как данные были перенесены в SQL Server из MySQL? Вот несколько вариантов:
Возвращает:
Предполагая, что это был прямой двоичный код (то есть преобразование # 2 выше), тогда результирующий GUID, если он будет преобразован в фактический
UNIQUEIDENTIFIER
, будет:Возвращает:
Что не так. И это оставляет нас с тремя вопросами:
источник
Вы всегда можете быть обеспокоены. ;)
Возможно, система была перенесена из какой-то другой системы, которая не поддерживает uniqueidentifier. Есть ли другие компромиссы, о которых вы не знаете?
Разработчик может не знать о типе uniqueidentifier. О чем еще они не знали?
Технически, хотя - это не должно быть серьезной проблемой.
источник