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バイトは、制約のオブジェクトIDの16進バージョンです。objectid
独自の保証されている名前は、一意である必要があります。Sybaseでもこれらの使用tabname_colname_objectid
ユニーク制約とプライマリキー制約の場合、Sybaseは使用します
tabname_colname_tabindid。tabindidは、テーブルIDとインデックスIDの文字列連結です。
これも一意性を保証します。
SQL Serverはこのスキームを使用しません。
SQL Server 2008と2017の両方で、システムが生成した名前の最後に8バイトの文字列を使用しますが、その最後の4バイトの生成方法に関してアルゴリズムが変更されました。
2008年の最後の4バイトは、符号付き整数カウンターを表し、負の値が最大の符号付き整数にラップobject_id
されること-16000057
で、by からオフセットされます。(の重要性16000057
は、これが連続して作成される間に適用される増分object_id
であることです)。これはまだ一意性を保証します。
2012年以降、制約のobject_idと、名前の最後の8文字を符号付きintの16進表現として処理して得られた整数の間にパターンがまったく表示されません。
2017年の呼び出しスタック内の関数名は、名前生成プロセスの一部としてGUIDを作成することを示しています(2008年には、私は言及していませんMDConstraintNameGenerator
)。これはランダム性のソースを提供するためだと思います。ただし、4バイトのGUIDから16バイト全体を使用しているのではなく、制約間で変更していることは明らかです。
あなたのような極端な場合に衝突の可能性がいくらか増加することを犠牲にして、新しいアルゴリズムは何らかの効率的な理由で行われたと思います。
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で実行された例は、1分以上で失敗しました(50,931テーブルが作成された後)
メッセージ2714、レベル16、状態30、行15データベースには既に「PK__abcdefgh__3BD019A8175067CE」という名前のオブジェクトがあります。メッセージ1750、レベル16、状態1、行15制約またはインデックスを作成できませんでした。以前のエラーを参照してください。