Tôi có nên thêm trường tăng tự động / IDENTITY vào bảng tham chiếu chéo chỉ cho mục đích PK không?


9

Tôi đang thêm bảng tham chiếu chéo sau vào DB được lưu trữ trên máy chủ SQL của mình:

company_id bigint not null (FK)
org_path nvarchar (2048) not null

Các company_idlĩnh vực liên quan đến các idlĩnh vực trong bảng khác (trong đó nó là khóa chính).

Cho rằng cũng có thể có nhiều bản ghi giống nhau company_id, bất kỳ khóa chính nào cũng sẽ phải sử dụng cả hai trường. Tuy nhiên, tôi không thể tạo khóa bằng cả hai trường vì org_pathquá dài cho SQL Server.

Đối với org_path, đây là bảng duy nhất mà nó tồn tại. Có nhiều khả năng các truy vấn vào bảng này sẽ yêu cầu tất cả các mục nhập hoặc tất cả org_pathcác mục nhập theo company_id. Hoặc để nó theo một cách khác, có vẻ nghi ngờ rằng bảng này sẽ được truy vấn bởi org_path. Hơn nữa, nó không chắc org_pathsẽ được cập nhật, và nhiều khả năng được chèn và - có lẽ hiếm khi - bị xóa.

Tôi hy vọng rằng tổng số hàng sẽ ở mức thấp.

Ngoài ra, lý do nvarchar (2048)là vì giá trị phải bắt chước trong DB của bên thứ ba. Một ví dụ điển hình sẽ là một cái gì đó như

\Translation Providers\[customer name]\[order name]\

và có thể chứa dấu phụ.

Vì vậy, câu hỏi của tôi là: sẽ hiệu quả hơn nếu thêm idtrường tăng tự động và sử dụng kết hợp với company_idlàm khóa chính hoặc nó sẽ thêm chi phí không cần thiết - và thực tế đó company_idlà khóa chính trong bảng khác có bất kỳ có tác dụng ở đây?

Câu trả lời:


7

Đối với một chỉ mục cụm không duy nhất trên comany_idmột mình, SQL Server sẽ tự động thêm một bộ duy nhất số nguyên 4 byte cho tất cả các khóa chỉ mục được sao chép (tức là thứ hai và tiếp theo cho một giá trị khóa) để làm cho nó trở thành duy nhất. Điều này không được tiếp xúc với người dùng mặc dù.

Ưu điểm của việc thêm số nhận dạng duy nhất của riêng bạn làm cột khóa phụ là bạn vẫn có thể tìm kiếm company_idnhưng cũng có thể tìm kiếm các hàng riêng lẻ hiệu quả hơn (sử dụng company_id, identitycolthay vì sử dụng company_idmột biến vị ngữ còn lại org_path). Chỉ mục được nhóm sau đó sẽ là duy nhất company_id, identitycol, vì vậy không có chỉ số ẩn nào được thêm vào.

Ngoài ra, nếu bạn kết thúc với các bản sao cho (company_id,org_path), việc có cột nhận dạng rõ ràng (một loại "công cụ duy nhất được hiển thị") sẽ giúp bạn dễ dàng nhắm mục tiêu chỉ một trong số chúng để xóa hoặc cập nhật.


12

Một điều cần xem xét là Khóa chính và Chỉ mục cụm không giống nhau. Khóa chính là một ràng buộc và liên quan đến các quy tắc mà dữ liệu tồn tại (tức là toàn vẹn dữ liệu); nó không có gì để làm với hiệu quả / hiệu suất. Khóa chính yêu cầu (các) cột khóa phải là duy nhất (kết hợp) và KHÔNG NULL (riêng lẻ). Một PK được thi hành thông qua một Chỉ mục duy nhất, mặc dù nó có thể được phân cụm hoặc không phân cụm.

Chỉ mục cụm là một phương tiện vật lý (tức là trên đĩa) sắp xếp dữ liệu trong bảng và xử lý hiệu suất; nó không có gì để làm với tính toàn vẹn dữ liệu. Một chỉ số cụm có thểyêu cầu (các) cột khóa là duy nhất (kết hợp), nhưng nó không cần. Tuy nhiên, vì Chỉ mục cụm là thứ tự vật lý của dữ liệu, nên nó cần xác định duy nhất mỗi hàng bất kể là gì. Vì vậy, nếu bạn không đặt nó để yêu cầu tính duy nhất, nó sẽ tạo ra tính duy nhất của riêng nó thông qua cột "uniquifier" 4 byte ẩn. Cột đó luôn có trong các Chỉ mục cụm không duy nhất, nhưng nó không chiếm bất kỳ khoảng trống nào khi các trường khóa là duy nhất (kết hợp). Để xem tận mắt cột "uniquifier" này hoạt động như thế nào (cả trong Chỉ mục cụm và hiệu ứng trên Chỉ mục không phân cụm), vui lòng kiểm tra tập lệnh kiểm tra này tôi đã đăng trên tập lệnh PasteBin: T-SQL để kiểm tra kích thước của Trình duy nhất .

Do đó, câu hỏi chính của:

nó sẽ hiệu quả hơn để thêm tự động tăng id trường và sử dụng trường đó company_idlàm khóa chính hoặc thêm chi phí không cần thiết

đang kết hợp hai khái niệm đó, vì vậy chúng cần được giải quyết một cách riêng biệt, mặc dù chắc chắn có một số chồng chéo.

Nên một IDENTITY cột nên được thêm vào hoặc nó sẽ là chi phí không cần thiết?

Nếu bạn thêm một INT IDENTITYcột và sử dụng nó để tạo PK, giả sử đó sẽ là PK cụm, có thêm 4 byte cho mỗi hàng. Cột này có thể nhìn thấy và có thể sử dụng trong các truy vấn. Nó có thể được thêm vào các bảng khác dưới dạng Khóa ngoài, mặc dù trong trường hợp cụ thể này sẽ không xảy ra.

Nếu bạn không thêm INT IDENTITY cột, thì bạn không thể tạo PK trên bảng này. Tuy nhiên, bạn vẫn có thể tạo Chỉ mục cụm trên bảng miễn là bạn không sử dụng UNIQUEtùy chọn. Trong trường hợp này, SQL Server sẽ thêm một cột ẩn gọi là "uniquifier" hoạt động như mô tả ở trên. Vì cột bị ẩn, nó không thể được sử dụng trong các truy vấn hoặc làm tài liệu tham khảo cho Khóa ngoại.

Về hiệu quả, các tùy chọn này gần như giống nhau. Có, sẽ có ít không gian hơn một chút khi có Chỉ số cụm không duy nhất do một số hàng (những hàng có giá trị khóa duy nhất ban đầu) chiếm 0 byte trong khi tất cả các hàng trong IDENTITY/ PK sẽ lấy 4 byte. Nhưng sẽ không có đủ các hàng 0 byte (đặc biệt là với số lượng hàng nhỏ dự kiến) sẽ nhận thấy sự khác biệt, chứ đừng nói đến việc cân nhắc sự tiện lợi của việc có thể sử dụngID cột trong các truy vấn.

Cột INTENTENT hoặc Hash của org_pathcột được tính toán bền vững?

Vì bạn sẽ không tìm kiếm các hàng dựa trên org_pathcác giá trị, nên sẽ không có ý nghĩa gì khi thêm chi phí của Cột được tính toán liên tục cộng với việc cần tính toán hàm băm đó trong các truy vấn để khớp với Cột được tính (đây là của tôi đề xuất ban đầu, có sẵn trong lịch sử sửa đổi ở đây , dựa trên từ ngữ / chi tiết ban đầu của Câu hỏi). Trong trường hợp cụ thể này, INT IDENTITYCột "ID" có lẽ là tốt nhất.

Thứ tự cột chính

Cho rằng IDCột sẽ hiếm khi được sử dụng trong các truy vấn cho rằng hai trường hợp sử dụng chính là lấy "tất cả các hàng" hoặc "tất cả các hàng cho một company_id" nhất định , tôi sẽ tạo PK trên company_id, id. Và bởi vì điều này có nghĩa là các hàng không được chèn liên tục, tôi sẽ chỉ định một FILLFACTORtrong 90. Bạn cũng sẽ cần đảm bảo duy trì chỉ số thường xuyên để giảm phân mảnh.

Câu hỏi thứ hai

thực tế rằng company_id là khóa chính trong một bảng khác có ảnh hưởng gì ở đây không

Không.

Kích hoạt

org_pathcác giá trị trong một company_idlà duy nhất, bạn vẫn nên tạo Kích hoạt INSERT, UPDATEđể thực thi điều này. Trong Kích hoạt, thực hiện IF EXISTSmột truy vấn có thể thực hiện một COUNT(*)GROUP BY company_id, org_path. Nếu tìm thấy bất cứ điều gì, hãy đưa ra yêu ROLLBACKcầu hủy bỏ hoạt động DML và sau đó RAISERRORnói rằng có các bản sao.

Đối chiếu

Trong câu trả lời ban đầu của tôi (dựa trên từ ngữ gốc / chi tiết thưa thớt của câu hỏi và có sẵn trong lịch sử sửa đổi ở đây ), tôi đã đề xuất có thể sử dụng Đối chiếu nhị phân (tức là _BIN2). Bây giờ chúng tôi có cái nhìn sâu sắc về chính xác org_pathlà gì , tôi không khuyên bạn nên sử dụng Collation nhị phân. Vì sẽ có dấu phụ, bạn không muốn sử dụng các tương đương ngôn ngữ.



0

Tại sao bạn cần PK?

Tại sao không đi với company_id như một chỉ mục không được nhóm?

Bạn cho biết hầu hết các tìm kiếm đều có trên tất cả các mục hoặc bởi company_id
Hiếm khi cập nhật
Hiếm khi xóa
org_path, đây là bảng duy nhất tồn tại

Câu trả lời từ Martin Smith có thể giúp bạn có được những gì bạn cần
Tôi không quen với việc tự động thêm một công cụ duy nhất số nguyên 4 byte
Có thể tôi đang thiếu một cái gì đó nhưng nếu bạn không có các cột khác được lập chỉ mục thì tôi không thấy mục đích này trong trường hợp sử dụng này

Nếu bạn lo lắng về DRI, các bảng nên sử dụng bảng Công ty làm FK cho company_id


Chào. Về " Tại sao không đi với company_id như một chỉ mục không được nhóm? ": Bởi vì điều đó sẽ có 2 mặt trái: 1) sẽ có thêm 1 thứ chiếm không gian trong khi Chỉ số cụm bảng để không có mục bổ sung và 2) nó vẫn sẽ yêu cầu tra cứu RID để có được trường NVARCHAR, trừ khi đó là một INCLUDEcột, nhưng điều đó thậm chí còn tệ hơn khi nó chỉ đơn thuần là sao chép bảng. Đúng, PK không cần thiết; phần quan trọng là Chỉ số cụm. Nhưng một khi bạn có SẮC, cũng có thể đi với PK. Và xin vui lòng xem liên kết mới trong câu trả lời của tôi để xem qua phần Uniquifier 😃
Solomon Rutzky

@srutzky Nhưng nó tránh được một công cụ duy nhất số nguyên 4 byte nên tôi thấy đó là một lần rửa
paparazzo

Với ít hơn 10 nghìn hàng, điều đó sẽ không thành vấn đề; bạn có thể cần phải ở trong hàng triệu hàng trước khi bạn nhận thấy hiệu ứng chỉ 4 byte. Vì vậy, đối với truy vấn "lấy tất cả các hàng" thực sự không có bất kỳ sự khác biệt nào trong bất kỳ tùy chọn nào trong số này. Nhưng đối với truy vấn "get for company_id = @param", việc dữ liệu được sắp xếp theo thứ tự của company_id sẽ giúp ích, đặc biệt là khi không cần thực hiện tra cứu RID cho mỗi hàng.
Solomon Rutzky

@srutzky Rửa là nước rửa - 10K hoặc 1G. Nó chỉ là một cái gì đó để OP xem xét.
paparazzo
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.