Bisakah SQL Server membuat tabrakan dalam nama kendala yang dihasilkan sistem?

14

Saya memiliki aplikasi yang membuat jutaan tabel dalam database SQL Server 2008 (non clustered). Saya mencari untuk meng-upgrade ke SQL Server 2014 (berkerumun), tetapi saya menekan pesan kesalahan ketika sedang dimuat:

"Sudah ada objek bernama 'PK__tablenameprefix__179E2ED8F259C33B' dalam database"

Ini adalah nama kendala yang dihasilkan sistem. Sepertinya nomor 64-bit yang dihasilkan secara acak. Mungkinkah saya melihat tabrakan karena banyaknya tabel? Dengan asumsi saya memiliki 100 juta tabel, saya menghitung kemungkinan tabrakan kurang dari 1 dalam 1 triliun ketika menambahkan tabel berikutnya, tetapi itu mengasumsikan distribusi yang seragam. Apakah mungkin bahwa SQL Server mengubah algoritma pembuatan nama antara versi 2008 dan 2014 untuk meningkatkan kemungkinan tabrakan?

Perbedaan signifikan lainnya adalah bahwa instance 2014 saya adalah pasangan berkerumun, tetapi saya berjuang untuk membentuk hipotesis mengapa itu akan menghasilkan kesalahan di atas.

PS Ya, saya tahu membuat jutaan tabel itu gila. Ini adalah kode pihak ke-3 kotak hitam yang tidak dapat saya kendalikan. Meskipun kegilaan, itu bekerja di versi 2008 dan sekarang tidak di versi 2014.

Sunting: pada pemeriksaan lebih dekat, akhiran yang dihasilkan sepertinya selalu dimulai dengan 179E2ED8 - yang berarti bagian acak sebenarnya hanya nomor 32-bit dan kemungkinan tabrakan hanya 1-in-50 setiap kali tabel baru ditambahkan, yang adalah pertandingan yang jauh lebih dekat dengan tingkat kesalahan yang saya lihat!

jl6
sumber
Nama-nama tabel berbeda tetapi mereka menggunakan konvensi penamaan yang menghasilkan setidaknya 11 karakter pertama yang sama, dan yang tampaknya semua SQL Server menggunakan dalam menghasilkan nama kendala.
jl6
Perangkat keras yang mendasarinya berbeda (generasi baru DL380) tetapi kinerjanya tidak jauh lebih tinggi. Tujuan dari latihan ini adalah untuk menggantikan dukungan SQL Server 2008, bukan untuk meningkatkan throughput, dan perangkat keras telah disediakan.
jl6

Jawaban:

15

Bisakah SQL Server membuat tabrakan dalam nama kendala yang dihasilkan sistem?

Ini tergantung pada jenis batasan dan versi 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

Contoh Hasil 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           |
+--------------------------+-----------+---------------+----------------------+

Contoh Hasil 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           |
+--------------------------+------------+---------------+----------------------+

Untuk batasan default, periksa batasan dan batasan kunci asing, 4 byte terakhir dari nama yang dihasilkan secara otomatis adalah versi hexadecimal dari objectid dari kendala. Seperti objectidyang dijamin unik namanya juga harus unik. Di Sybase juga menggunakan initabname_colname_objectid

Untuk batasan unik dan batasan kunci primer yang digunakan Sybase

tabname_colname_tabindid, di mana tabindid adalah rangkaian string ID tabel dan ID indeks

Ini juga akan menjamin keunikan.

SQL Server tidak menggunakan skema ini.

Dalam SQL Server 2008 dan 2017 menggunakan string 8 byte pada akhir nama sistem yang dihasilkan namun algoritma telah berubah tentang bagaimana 4 byte terakhir yang dihasilkan.

Pada tahun 2008, 4 byte terakhir mewakili penghitung bilangan bulat yang ditandatangani yang diimbangi object_idoleh -16000057dengan nilai negatif apa pun yang membungkus hingga maksimum yang ditandatangani. (Signifikansi 16000057adalah bahwa ini adalah kenaikan yang diterapkan antara yang dibuat secara berturut-turutobject_id ). Ini masih menjamin keunikan.

Pada 2012 ke atas saya tidak melihat pola sama sekali antara object_id dari kendala dan integer yang diperoleh dengan memperlakukan 8 karakter terakhir dari nama sebagai representasi heksadesimal dari int yang ditandatangani.

Nama-nama fungsi di tumpukan panggilan pada 2017 menunjukkan bahwa itu sekarang membuat GUID sebagai bagian dari proses pembuatan nama (Pada 2008 saya tidak melihat menyebutkan MDConstraintNameGenerator). Saya kira ini untuk memberikan beberapa sumber keacakan. Jelas itu tidak menggunakan keseluruhan 16 byte dari GUID dalam 4 byte yang mengubah kendala.

masukkan deskripsi tautan di sini

Saya kira algoritma baru dilakukan untuk beberapa alasan efisiensi dengan mengorbankan beberapa kemungkinan peningkatan tabrakan dalam kasus-kasus ekstrim seperti milik Anda.

Ini adalah kasus yang cukup patologis karena memerlukan awalan nama tabel dan nama kolom PK (sejauh ini mempengaruhi 8 karakter sebelum 8 akhir) untuk identik untuk puluhan ribu tabel sebelum menjadi kemungkinan tetapi dapat direproduksi cukup dengan mudah dengan di bawah ini.

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

Contoh berjalan pada SQL Server 2017 terhadap database yang baru dibuat gagal hanya dalam satu menit (setelah 50.931 tabel dibuat)

Msg 2714, Level 16, Negara 30, Jalur 15 Sudah ada objek bernama 'PK__abcdefgh__3BD019A8175067CE' dalam database. Msg 1750, Level 16, Negara 1, Jalur 15 Tidak dapat membuat batasan atau indeks. Lihat kesalahan sebelumnya.

Martin Smith
sumber
11

Dengan asumsi saya memiliki 100 juta tabel, saya menghitung kemungkinan tabrakan kurang dari 1 dalam 1 triliun

Ingat ini adalah " masalah ulang tahun ". Anda tidak mencoba untuk menghasilkan collision untuk hash tunggal, tetapi mengukur probabilitas bahwa tidak satu pun dari banyak pasangan nilai yang akan bertabrakan.

Jadi dengan N tabel, ada N * (N-1) / 2 pasang, jadi di sini sekitar 10 16 pasang. Jika probabilitas tabrakan adalah 2 -64 , probabilitas satu pasangan tidak bertabrakan adalah 1-2 -64 , tetapi dengan begitu banyak pasangan, kemungkinan tidak ada tabrakan di sini adalah sekitar (1-2 -64 ) 10 16 , atau lebih seperti 1 / 10.000. Lihat misalnya https://preshing.com/20110504/hash-collision-probabilities/

Dan jika itu hanya hash 32bit kemungkinan tabrakan melintasi 1/2 hanya pada nilai 77k.

David Browne - Microsoft
sumber
2
Dan untuk mendapatkan nilai 77K di tempat pertama tanpa menemukan tabrakan sepertinya sangat tidak mungkin karena Anda harus beruntung untuk semua kreasi sebelumnya sebelum itu. Saya ingin tahu apa intinya di mana probabilitas kumulatif tabrakan mencapai 50%
Martin Smith