У меня есть приложение, которое создает миллионы таблиц в базе данных SQL Server 2008 (не кластеризовано). Я ищу обновление до SQL Server 2014 (кластеризованный), но при загрузке появляется сообщение об ошибке:
«В базе данных уже есть объект с именем PK__tablenameprefix__179E2ED8F259C33B»
Это сгенерированное системой имя ограничения. Это выглядит как случайно сгенерированное 64-битное число. Возможно ли, что я вижу столкновения из-за большого количества таблиц? Предполагая, что у меня 100 миллионов таблиц, при добавлении следующей таблицы я вычисляю вероятность столкновения менее 1-на-триллион, но это предполагает равномерное распределение. Возможно ли, что SQL Server изменил свой алгоритм генерации имен между версиями 2008 и 2014, чтобы увеличить вероятность столкновения?
Другое существенное отличие состоит в том, что мой экземпляр 2014 года является кластерной парой, но я изо всех сил пытаюсь сформировать гипотезу о том, почему это вызвало бы вышеуказанную ошибку.
PS Да, я знаю, создание миллионов столов безумие. Это черный ящик стороннего кода, который я не могу контролировать. Несмотря на безумие, он работал в версии 2008 года, а теперь нет в версии 2014.
Редактировать: при ближайшем рассмотрении сгенерированный суффикс, кажется, всегда начинается с 179E2ED8 - это означает, что случайная часть на самом деле является всего лишь 32-битным числом, а шансы коллизий равны 1 к 50 при каждом добавлении новой таблицы, что это намного ближе к уровню ошибок, который я вижу!
Ответы:
Это зависит от типа ограничения и версии SQL Server.
Пример результатов 2008
Пример результатов 2017
Для ограничений по умолчанию, проверочных ограничений и ограничений внешнего ключа последние 4 байта автоматически сгенерированного имени являются шестнадцатеричной версией объекта ограничения. Поскольку
objectid
гарантировано уникальное имя также должно быть уникальным. В Sybase тоже этим пользуютсяtabname_colname_objectid
Для уникальных ограничений и ограничений первичного ключа Sybase использует
Это также гарантировало бы уникальность.
SQL Server не использует эту схему.
В SQL Server 2008 и 2017 он использует 8-байтовую строку в конце имени, сгенерированного системой, однако алгоритм изменился относительно того, как генерируются последние 4 байта.
В 2008 году последние 4 байта представляют счетчик целых чисел со знаком, который смещен от
object_id
by,-16000057
причем любое отрицательное значение оборачивается до максимального знакового целого числа . (Значение16000057
заключается в том, что это приращение применяется между последовательно созданнымиobject_id
). Это по-прежнему гарантирует уникальность.Начиная с 2012 года, я не вижу никакого паттерна между object_id ограничения и целым числом, полученным обработкой последних 8 символов имени как шестнадцатеричное представление целого числа со знаком.
Имена функций в стеке вызовов в 2017 году показывают, что теперь он создает GUID как часть процесса генерации имени (в 2008 году я не вижу упоминания
MDConstraintNameGenerator
). Я предполагаю, что это должно обеспечить некоторый источник случайности. Ясно, что он не использует все 16 байтов из GUID в этих 4 байтах, которые меняются между ограничениями.Я предполагаю, что новый алгоритм был сделан по некоторой причине эффективности за счет некоторой увеличенной вероятности столкновений в крайних случаях, таких как ваш.
Это довольно патологический случай, поскольку он требует, чтобы префикс имени таблицы и имя столбца PK (поскольку это влияет на 8 символов, предшествующих последним 8), должны быть идентичными для десятков тысяч таблиц, прежде чем это станет вероятным, но может быть воспроизведено довольно легко с ниже.
Пример запуска на SQL Server 2017 для вновь созданной базы данных завершился неудачей всего за минуту (после создания 50 931 таблицы)
источник
Помните, что это « проблема дня рождения ». Вы не пытаетесь сгенерировать коллизию для одного данного хэша, а скорее измеряете вероятность того, что ни одна из множества пар значений не столкнется.
Таким образом, с N таблицами есть N * (N-1) / 2 пары, так что здесь около 10 16 пар. Если вероятность столкновения составляет 2 -64 , вероятность того, что одна пара не столкнется, составляет 1-2 -64 , но при таком количестве пар вероятность отсутствия столкновений здесь составляет около (1-2 -64 ) 10 16. или больше, как 1/10000. Смотрите, например, https://preshing.com/20110504/hash-collision-probabilities/.
И если это всего лишь 32-битный хэш, вероятность столкновения пересекает 1/2 только при 77k значениях.
источник