Может ли 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 при каждом добавлении новой таблицы, что это намного ближе к уровню ошибок, который я вижу!


Имена таблиц различны, но в них используется соглашение об именах, в результате которого по меньшей мере первые 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 значениях.


2
И получить значения 77K во-первых, не столкнувшись со столкновением, скорее всего, маловероятно, так как вам нужно было повезти во всех предыдущих созданиях до этого. Интересно, в чем смысл, когда совокупная вероятность столкновения достигает 50%
— Мартин Смит,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.