SQL Server có thể tạo xung đột trong các tên ràng buộc do hệ thống tạo không?


14

Tôi có một ứng dụng tạo ra hàng triệu bảng trong cơ sở dữ liệu SQL Server 2008 (không được phân cụm). Tôi đang tìm cách nâng cấp lên SQL Server 2014 (cụm), nhưng đang gặp thông báo lỗi khi tải:

Đã có một đối tượng tên là 'PK__tablenameprefix__179E2ED8F259C33B' trong cơ sở dữ liệu

Đây là một tên ràng buộc hệ thống tạo ra. Nó trông giống như một số 64 bit được tạo ngẫu nhiên. Có thể là tôi đang thấy va chạm do số lượng lớn các bảng? Giả sử tôi có 100 triệu bảng, tôi tính ít hơn khả năng xảy ra va chạm 1 trong 1 nghìn tỷ khi thêm bảng tiếp theo, nhưng điều đó giả sử phân phối đồng đều. Có thể SQL Server đã thay đổi thuật toán tạo tên giữa phiên bản 2008 và 2014 để tăng tỷ lệ va chạm?

Sự khác biệt đáng kể khác là phiên bản 2014 của tôi là một cặp, nhưng tôi đang vật lộn để tạo ra một giả thuyết về lý do tại sao điều đó sẽ tạo ra lỗi trên.

PS Có, tôi biết việc tạo ra hàng triệu bảng là điên rồ. Đây là hộp đen mã bên thứ 3 mà tôi không kiểm soát được. Bất chấp sự điên rồ, nó đã hoạt động trong phiên bản 2008 và hiện không có trong phiên bản 2014.

Chỉnh sửa: khi kiểm tra kỹ hơn, hậu tố được tạo dường như luôn bắt đầu bằng 179E2ED8 - có nghĩa là phần ngẫu nhiên thực sự chỉ là một số 32 bit và tỷ lệ va chạm chỉ là 1 trong 50 mỗi khi một bảng mới được thêm vào. là một kết hợp gần hơn với tỷ lệ lỗi tôi đang thấy!


Tên bảng là khác nhau nhưng chúng sử dụng quy ước đặt tên dẫn đến ít nhất 11 ký tự đầu tiên giống nhau và đó dường như là tất cả SQL Server sử dụng để tạo tên ràng buộc.
jl6

Phần cứng cơ bản là khác nhau (thế hệ mới hơn của DL380) nhưng hiệu suất không cao hơn đáng kể. Mục đích của bài tập là thay thế SQL Server 2008 hỗ trợ, không phải để cải thiện thông lượng và phần cứng đã được cung cấp tương ứng.
jl6

Câu trả lời:


15

SQL Server có thể tạo xung đột trong các tên ràng buộc do hệ thống tạo không?

Điều này phụ thuộc vào loại ràng buộc và phiên bản của 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

Kết quả ví dụ 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           |
+--------------------------+-----------+---------------+----------------------+

Kết quả ví dụ 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           |
+--------------------------+------------+---------------+----------------------+

Đối với các ràng buộc mặc định, kiểm tra các ràng buộc và ràng buộc khóa ngoài, 4 byte cuối cùng của tên được tạo tự động là phiên bản thập lục phân của đối tượng của ràng buộc. Như objectidđược đảm bảo duy nhất, tên cũng phải là duy nhất. Trong Sybase cũng vậy những sử dụngtabname_colname_objectid

Đối với các ràng buộc duy nhất và các ràng buộc khóa chính, Sybase sử dụng

tabname_colname_tabindid, trong đó tabindid là một chuỗi nối của ID bảng và ID chỉ mục

Điều này cũng sẽ đảm bảo tính độc đáo.

SQL Server không sử dụng lược đồ này.

Trong cả SQL Server 2008 và 2017, nó sử dụng chuỗi 8 byte ở cuối tên được tạo bởi hệ thống, tuy nhiên thuật toán đã thay đổi như cách tạo ra 4 byte cuối cùng.

Trong năm 2008, 4 byte cuối cùng biểu thị một bộ đếm số nguyên đã ký được bù từ object_idbởi -16000057với bất kỳ giá trị âm nào được bao quanh đến int được ký tối đa. (Ý nghĩa của 16000057việc này là mức tăng được áp dụng giữa các lần tạo liên tiếpobject_id ). Điều này vẫn đảm bảo tính độc đáo.

Vào năm 2012 trở đi, tôi không thấy bất kỳ mẫu nào ở giữa object_id của ràng buộc và số nguyên thu được bằng cách coi 8 ký tự cuối cùng của tên là biểu diễn thập lục phân của một int đã ký.

Các tên hàm trong ngăn xếp cuộc gọi năm 2017 cho thấy rằng bây giờ nó tạo GUID như một phần của quy trình tạo tên (Vào năm 2008 tôi không thấy đề cập đến MDConstraintNameGenerator). Tôi đoán điều này là để cung cấp một số nguồn ngẫu nhiên. Rõ ràng là nó không sử dụng toàn bộ 16 byte từ GUID trong 4 byte đó thay đổi giữa các ràng buộc.

nhập mô tả liên kết ở đây

Tôi cho rằng thuật toán mới đã được thực hiện vì một số lý do hiệu quả với chi phí tăng khả năng va chạm trong các trường hợp cực đoan như của bạn.

Đây là một trường hợp bệnh lý vì nó yêu cầu tiền tố tên bảng và tên cột của PK (trong trường hợp này ảnh hưởng đến 8 ký tự trước 8 ký tự cuối cùng) giống hệt nhau cho hàng chục nghìn bảng trước khi có thể xảy ra nhưng có thể được sao chép hoàn toàn dễ dàng với những điều dưới đây

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

Một ví dụ chạy trên SQL Server 2017 đối với cơ sở dữ liệu mới được tạo không thành công chỉ sau hơn một phút (sau khi 50.931 bảng đã được tạo)

Msg 2714, Cấp 16, Bang 30, Dòng 15 Đã có một đối tượng có tên 'PK__abcdefgh__3BD019A8175067CE' trong cơ sở dữ liệu. Msg 1750, Cấp 16, Trạng thái 1, Dòng 15 Không thể tạo ràng buộc hoặc chỉ mục. Xem các lỗi trước.


11

Giả sử tôi có 100 triệu bảng, tôi tính ít hơn khả năng xảy ra va chạm 1 trong 1 nghìn tỷ

Hãy nhớ rằng đây là " vấn đề sinh nhật ". Bạn không cố tạo ra xung đột cho một hàm băm nhất định, mà là đo xác suất không có cặp nào trong số nhiều cặp giá trị sẽ va chạm.

Vì vậy, với N bảng, có cặp N * (N-1) / 2, vì vậy ở đây có khoảng 10 16 cặp. Nếu xác suất va chạm là 2 -64 , xác suất một cặp không va chạm là 1-2 -64 , nhưng với rất nhiều cặp, xác suất không có va chạm ở đây là khoảng (1-2 -64 ) 10 16 hoặc nhiều hơn như 1 / 10.000. Xem ví dụ: https://preshing.com/20110504/hash-collision-probabilities/

Và nếu đó chỉ là băm 32 bit thì xác suất xảy ra va chạm vượt qua 1/2 với giá trị chỉ 77k.


2
Và để có được giá trị 77K ở vị trí đầu tiên mà không gặp phải va chạm có thể là không thể thực hiện được vì bạn cần phải may mắn cho tất cả các sáng tạo trước đó. Tôi tự hỏi vấn đề là gì khi xác suất tích lũy của một vụ va chạm lên tới 50%
Martin Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.