Может ли SQL Server создавать конфликты в сгенерированных системой именах ограничений?

14

У меня есть приложение, которое создает миллионы таблиц в базе данных SQL Server 2008 (не кластеризовано). Я ищу обновление до SQL Server 2014 (кластеризованный), но при загрузке появляется сообщение об ошибке:

«В базе данных уже есть объект с именем PK__tablenameprefix__179E2ED8F259C33B»

Это сгенерированное системой имя ограничения. Это выглядит как случайно сгенерированное 64-битное число. Возможно ли, что я вижу столкновения из-за большого количества таблиц? Предполагая, что у меня 100 миллионов таблиц, при добавлении следующей таблицы я вычисляю вероятность столкновения менее 1-на-триллион, но это предполагает равномерное распределение. Возможно ли, что SQL Server изменил свой алгоритм генерации имен между версиями 2008 и 2014, чтобы увеличить вероятность столкновения?

Другое существенное отличие состоит в том, что мой экземпляр 2014 года является кластерной парой, но я изо всех сил пытаюсь сформировать гипотезу о том, почему это вызвало бы вышеуказанную ошибку.

PS Да, я знаю, создание миллионов столов безумие. Это черный ящик стороннего кода, который я не могу контролировать. Несмотря на безумие, он работал в версии 2008 года, а теперь нет в версии 2014.

Редактировать: при ближайшем рассмотрении сгенерированный суффикс, кажется, всегда начинается с 179E2ED8 - это означает, что случайная часть на самом деле является всего лишь 32-битным числом, а шансы коллизий равны 1 к 50 при каждом добавлении новой таблицы, что это намного ближе к уровню ошибок, который я вижу!

jl6
источник
Имена таблиц различны, но в них используется соглашение об именах, в результате которого по меньшей мере первые 11 символов совпадают, и, похоже, это все, что SQL Server использует при создании имени ограничения.
JL6
Базовое оборудование отличается (новое поколение DL380), но не значительно более высокой производительностью. Цель этого упражнения - заменить устаревшую версию SQL Server 2008, а не повысить пропускную способность, и оборудование было соответствующим образом подготовлено.
JL6

Ответы:

15

Может ли SQL Server создавать конфликты в сгенерированных системой именах ограничений?

Это зависит от типа ограничения и версии SQL Server.

CREATE TABLE T1
(
A INT PRIMARY KEY CHECK (A > 0),
B INT DEFAULT -1 REFERENCES T1,
C INT UNIQUE,
CHECK (C > A)
)

SELECT name, 
       object_id, 
       CAST(object_id AS binary(4)) as object_id_hex,
       CAST(CASE WHEN object_id >= 16000057  THEN object_id -16000057 ELSE object_id +2131483591 END AS BINARY(4)) AS object_id_offset_hex
FROM sys.objects
WHERE parent_object_id = OBJECT_ID('T1')
ORDER BY name;

drop table T1

Пример результатов 2008

+--------------------------+-----------+---------------+----------------------+
|           name           | object_id | object_id_hex | object_id_offset_hex |
+--------------------------+-----------+---------------+----------------------+
| CK__T1__1D498357         | 491357015 | 0x1D498357    | 0x1C555F1E           |
| CK__T1__A__1A6D16AC      | 443356844 | 0x1A6D16AC    | 0x1978F273           |
| DF__T1__B__1B613AE5      | 459356901 | 0x1B613AE5    | 0x1A6D16AC           |
| FK__T1__B__1C555F1E      | 475356958 | 0x1C555F1E    | 0x1B613AE5           |
| PK__T1__3BD019AE15A8618F | 379356616 | 0x169C85C8    | 0x15A8618F           |
| UQ__T1__3BD019A91884CE3A | 427356787 | 0x1978F273    | 0x1884CE3A           |
+--------------------------+-----------+---------------+----------------------+

Пример результатов 2017

+--------------------------+------------+---------------+----------------------+
|           name           | object_id  | object_id_hex | object_id_offset_hex |
+--------------------------+------------+---------------+----------------------+
| CK__T1__59FA5E80         | 1509580416 | 0x59FA5E80    | 0x59063A47           |
| CK__T1__A__571DF1D5      | 1461580245 | 0x571DF1D5    | 0x5629CD9C           |
| DF__T1__B__5812160E      | 1477580302 | 0x5812160E    | 0x571DF1D5           |
| FK__T1__B__59063A47      | 1493580359 | 0x59063A47    | 0x5812160E           |
| PK__T1__3BD019AE0A4A6932 | 1429580131 | 0x5535A963    | 0x5441852A           |
| UQ__T1__3BD019A981F522E0 | 1445580188 | 0x5629CD9C    | 0x5535A963           |
+--------------------------+------------+---------------+----------------------+

Для ограничений по умолчанию, проверочных ограничений и ограничений внешнего ключа последние 4 байта автоматически сгенерированного имени являются шестнадцатеричной версией объекта ограничения. Поскольку objectidгарантировано уникальное имя также должно быть уникальным. В Sybase тоже этим пользуютсяtabname_colname_objectid

Для уникальных ограничений и ограничений первичного ключа Sybase использует

tabname_colname_tabindid, где tabindid - конкатенация строк идентификатора таблицы и идентификатора индекса

Это также гарантировало бы уникальность.

SQL Server не использует эту схему.

В SQL Server 2008 и 2017 он использует 8-байтовую строку в конце имени, сгенерированного системой, однако алгоритм изменился относительно того, как генерируются последние 4 байта.

В 2008 году последние 4 байта представляют счетчик целых чисел со знаком, который смещен от object_idby, -16000057причем любое отрицательное значение оборачивается до максимального знакового целого числа . (Значение 16000057заключается в том, что это приращение применяется между последовательно созданнымиobject_id ). Это по-прежнему гарантирует уникальность.

Начиная с 2012 года, я не вижу никакого паттерна между object_id ограничения и целым числом, полученным обработкой последних 8 символов имени как шестнадцатеричное представление целого числа со знаком.

Имена функций в стеке вызовов в 2017 году показывают, что теперь он создает GUID как часть процесса генерации имени (в 2008 году я не вижу упоминания MDConstraintNameGenerator). Я предполагаю, что это должно обеспечить некоторый источник случайности. Ясно, что он не использует все 16 байтов из GUID в этих 4 байтах, которые меняются между ограничениями.

введите описание ссылки здесь

Я предполагаю, что новый алгоритм был сделан по некоторой причине эффективности за счет некоторой увеличенной вероятности столкновений в крайних случаях, таких как ваш.

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

CREATE OR ALTER PROC #P
AS
    SET NOCOUNT ON;

    DECLARE @I INT = 0;


    WHILE 1 = 1
      BEGIN
          EXEC ('CREATE TABLE abcdefghijklmnopqrstuvwxyz' + @I + '(C INT PRIMARY KEY)');
          SET @I +=1;
      END 

GO

EXEC #P

Пример запуска на SQL Server 2017 для вновь созданной базы данных завершился неудачей всего за минуту (после создания 50 931 таблицы)

Сообщение 2714, уровень 16, состояние 30, строка 15 В базе данных уже есть объект с именем PK__abcdefgh__3BD019A8175067CE. Сообщение 1750, уровень 16, состояние 1, строка 15 Не удалось создать ограничение или индекс. Смотрите предыдущие ошибки.

Мартин Смит
источник
11

Предполагая, что у меня 100 миллионов таблиц, я рассчитываю, что вероятность столкновения составляет менее 1 триллиона

Помните, что это « проблема дня рождения ». Вы не пытаетесь сгенерировать коллизию для одного данного хэша, а скорее измеряете вероятность того, что ни одна из множества пар значений не столкнется.

Таким образом, с 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 значениях.

Дэвид Браун - Microsoft
источник
2
И получить значения 77K во-первых, не столкнувшись со столкновением, скорее всего, маловероятно, так как вам нужно было повезти во всех предыдущих созданиях до этого. Интересно, в чем смысл, когда совокупная вероятность столкновения достигает 50%
Мартин Смит,