SQL Server sistem tarafından oluşturulan kısıtlama adlarında çakışmalar oluşturabilir mi?


14

Bir SQL Server 2008 veritabanında (kümelenmemiş) milyonlarca tablo oluşturan bir uygulama var. SQL Server 2014'e (kümelenmiş) yükseltmek istiyorum, ancak yük altında bir hata iletisi vuruyorum:

“Veritabanında zaten 'PK__tablenameprefix__179E2ED8F259C33B' adlı bir nesne var”

Bu, sistem tarafından oluşturulan bir kısıtlama adıdır. Rastgele oluşturulmuş bir 64 bit sayı gibi görünüyor. Çok sayıda tablo nedeniyle çarpışma görmem mümkün mü? 100 milyon tablom olduğu varsayılarak, bir sonraki tabloyu eklerken 1-in-1-trilyondan daha az çarpışma şansı hesaplıyorum, ancak bu tekdüze bir dağılım varsayıyor. SQL Server'ın, çarpışma olasılığını artırmak için 2008 ve 2014 sürümleri arasında ad oluşturma algoritmasını değiştirmesi mümkün müdür?

Diğer önemli fark, 2014 örneğimin kümelenmiş bir çift olması, ancak bunun neden yukarıdaki hatayı oluşturacağına dair bir hipotez oluşturmak için mücadele ediyorum.

PS Evet, milyonlarca tablo oluşturmanın çılgınca olduğunu biliyorum. Bu, üzerinde hiçbir kontrole sahip olmadığım kara kutu 3. parti kodu. Deliliğe rağmen, 2008 sürümünde çalıştı ve şimdi 2014 sürümünde çalışmıyor.

Düzenleme: daha yakından incelendiğinde, oluşturulan ek her zaman 179E2ED8 ile başlıyor gibi görünüyor - yani rastgele bölüm aslında sadece 32-bit bir sayıdır ve her yeni tablo eklendiğinde çarpışma olasılıkları sadece 1-in-50'dir. gördüğüm hata oranına çok daha yakın bir eşleşme!


Tablo adları farklıdır, ancak en az ilk 11 karakterin aynı olmasına neden olan bir adlandırma kuralı kullanırlar ve bu, SQL Server'ın kısıtlama adı oluştururken kullandığı gibi görünür.
jl6

Temel donanım farklıdır (yeni nesil DL380), ancak önemli ölçüde daha yüksek performans değildir. Alıştırmanın amacı, verimi artırmak için desteklenmeyen SQL Server 2008'in yerini almaktır ve donanım buna göre sağlanmıştır.
jl6

Yanıtlar:


16

SQL Server sistem tarafından oluşturulan kısıtlama adlarında çakışmalar oluşturabilir mi?

Bu, kısıtlama türüne ve SQL Server sürümüne bağlıdır.

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

Örnek Sonuçlar 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           |
+--------------------------+-----------+---------------+----------------------+

Örnek Sonuçlar 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           |
+--------------------------+------------+---------------+----------------------+

Varsayılan kısıtlamalar için, kontrol kısıtlamaları ve yabancı anahtar kısıtlamaları, otomatik oluşturulan adın son 4 baytı, sınırlamanın nesne kimliğinin onaltılık sürümüdür. objectidBenzersiz garantili olduğu gibi ad da benzersiz olmalıdır. Sybase'de de bu kullanımtabname_colname_objectid

Sybase'in kullandığı benzersiz kısıtlamalar ve birincil anahtar kısıtlamaları için

tabname_colname_tabindid; burada tabindid, tablo kimliğinin ve dizin kimliğinin dize birleşimidir

Bu da benzersizliği garanti eder.

SQL Server bu düzeni kullanmaz.

Hem SQL Server 2008 hem de 2017'de sistem tarafından üretilen adın sonunda 8 baytlık bir dize kullanır, ancak algoritma, son 4 baytın nasıl üretildiğine göre değişmiştir.

2008 yılında son 4 bayt kaymış bir imzalı tamsayı sayacı temsil object_idtarafından -16000057azami imzalı int etrafında herhangi bir olumsuz değer sarma ile. (Bunun önemi 16000057, bunun art arda oluşturulanlar arasında uygulanan artış olmasıdırobject_id ). Bu hala benzersizliği garanti eder.

2012 yılında, kısıtlamanın object_id değeri ile ismin son 8 karakterini imzalı bir int'in onaltılı gösterimi olarak ele alarak elde edilen tamsayı arasında hiçbir desen görmüyorum.

2017'deki çağrı yığınındaki işlev adları, artık ad oluşturma işleminin bir parçası olarak bir GUID oluşturduğunu göstermektedir (2008'de hiç bahsetmiyorum MDConstraintNameGenerator). Sanırım bu bir rastgelelik kaynağı sağlamak. Açıkçası, bu 4 baytta GUID'den 16 baytın tamamını kullanmıyor ancak kısıtlamalar arasında değişiyor.

bağlantı açıklamasını buraya girin

Yeni algoritmanın, sizinki gibi aşırı durumlarda bazı artan çarpışma olasılığı pahasına bir miktar verimlilik nedeni ile yapıldığını düşünüyorum.

PK'nın tablo adı önekini ve sütun adını (bu son 8'den önceki 8 karakteri etkilediği sürece) olası hale gelmeden önce on binlerce tablo için aynı olmasını gerektirdiğinden, ancak oldukça çoğaltılabildiğinden, bu oldukça patolojik bir durumdur. aşağıdaki ile kolayca.

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'de yeni oluşturulan bir veritabanında çalıştırılan örnek bir dakika içinde başarısız oldu (50.931 tablo oluşturulduktan sonra)

Msg 2714, Seviye 16, Durum 30, Satır 15 Veritabanında zaten 'PK__abcdefgh__3BD019A8175067CE' adlı bir nesne var. Msg 1750, Seviye 16, Durum 1, Satır 15 Kısıtlama veya dizin oluşturulamadı. Önceki hatalara bakın.


11

100 milyon tablom olduğu varsayılarak, 1-in-1-trilyondan az çarpışma şansı hesaplıyorum

Bunun " doğum günü sorunu " olduğunu unutmayın. Belirli bir karma için çarpışma oluşturmaya çalışmıyorsunuz, daha çok değer çiftlerinin hiçbirinin çarpışma olasılığını ölçüyorsunuz.

N tablolarda N * (N-1) / 2 çift var, bu yüzden burada yaklaşık 10 16 çift ​​var. Bir çarpışma olasılığı 2-64 ise , tek bir çiftin çarpışma olasılığı 1-2-64'tür , ancak çok fazla çiftle, ​​burada çarpışma olasılığı yaklaşık (1-2 -64 ) 10 16 veya 1 / 10.000 gibi. Bkz. Örneğin https://preshing.com/20110504/hash-collision-probability/

Ve eğer sadece 32 bitlik bir karma ise, bir çarpışma olasılığı sadece 77k değerlerde 1/2'yi geçer.


2
Ve bir çarpışma ile karşılaşmadan ilk etapta 77K değerlerine ulaşmak, muhtemelen önceki tüm kreasyonlar için şanslı olmanız gerektiğinden oldukça imkansızdır. Bir çarpışma olasılığının% 50'ye ulaştığı noktanın ne olduğunu merak ediyorum
Martin Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.