Чи може 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_id
по -16000057
будь-якому від'ємного значення обертати навколо максимальні підписаних межд. (Значення 16000057
полягає в тому, що це приріст, застосовуваний між послідовно створенимиobject_id
). Це все ще гарантує унікальність.
У 2012 році вгору я взагалі не бачу жодного шаблону між object_id обмеження та цілим числом, отриманим обробкою останніх 8 символів імені як шістнадцятковим поданням підписаного int.
Імена функцій у стеку викликів у 2017 році показують, що тепер він створює GUID як частину процесу генерації імен (про 2008 рік я не бачу жодної згадки MDConstraintNameGenerator
). Я гадаю, це полягає в тому, щоб створити певне джерело випадковості. Зрозуміло, що він не використовує цілих 16 байт з GUID у тих 4 байтах, які змінюються між обмеженнями.
Я припускаю, що новий алгоритм був зроблений з якихось причин ефективності за рахунок дещо підвищеної можливості зіткнень у крайніх випадках, таких як ваш.
Це досить патологічний випадок, оскільки для нього потрібен префікс назви таблиці та назва стовпця ПК (якщо це впливає на 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 таблиці)
Msg 2714, рівень 16, стан 30, рядок 15 У базі даних вже є об’єкт з назвою "PK__abcdefgh__3BD019A8175067CE". Msg 1750, рівень 16, стан 1, рядок 15 Не вдалося створити обмеження чи покажчик. Дивіться попередні помилки.