Bất kỳ cách nào xung quanh chỉ mục duy nhất tối đa 16 cột


8

Theo CREATE INDEXtài liệu:

Có thể kết hợp tối đa 16 cột thành một khóa chỉ mục tổng hợp duy nhất.

Chúng tôi đã có một bảng với ~ 18 cột cần tạo thành một sự kết hợp độc đáo. Bảng này không nhạy cảm về hiệu suất - chúng tôi hiếm khi cập nhật giá trị / chèn bản ghi. Chúng tôi chỉ cần đảm bảo rằng chúng tôi tránh trùng lặp hồ sơ của mình ... và nghĩ rằng chúng tôi có thể áp đặt một ràng buộc duy nhất đơn giản.

Có ý kiến ​​gì không? Tôi sẵn sàng tránh hoàn toàn chỉ số / ràng buộc nếu có cách tốt hơn.


4
Đó là một cái bàn.

@Joe: không bất thường trong một số trường hợp khi bạn đã kết hợp các kiểu con tương tự thành một. Trong trường hợp của tôi, một khóa 15 cột được yêu cầu thay vì hơn 50 bảng khác nhau. Một quyết định thực hiện ...
gbn

Trong khi những gì bạn đang hỏi là có thể, tôi không chắc nó là khôn ngoan. Bạn không đi theo con đường bị đánh đập. Như vậy, bạn đang ở trong sự ngạc nhiên. Bạn có nhiều khả năng học hỏi về những sai lầm của chính bạn hơn là của người khác. Về lâu dài có thể dễ dàng hơn để thử một cách tiếp cận thông thường hơn. Nếu bạn đăng thêm chi tiết, chúng tôi có thể giúp thực hiện.
AK

Tôi biết rằng đã được một lúc, nhưng điều gì ngăn bạn sử dụng cột nhận dạng GUID?
Robert Harvey

Câu trả lời:


14

Thêm một cột được tính toán bền bỉ kết hợp 18 khóa, sau đó tạo một chỉ mục duy nhất trên cột được tính:

alter table t add all_keys as c1+c2+c3+...+c18 persisted;
create unique index i18 on t (all_keys);

Xem Tạo chỉ mục trên các cột được tính toán .

Một cách tiếp cận khác là tạo ra một khung nhìn được lập chỉ mục:

create view v 
with schemabinding
as select c1+c2+c3+...+c18 as all_keys
from dbo.t;

create unique clustered index c18 on v(all_keys);

Xem Tạo Chế độ xem được lập chỉ mục .

Cả hai cách tiếp cận đều cho phép tổng hợp khóa một phần: tổng hợp c1 + c2 + c3 là k1, c4 + c5 + c6 là k2, v.v. sau đó lập chỉ mục / tạo chế độ xem được lập chỉ mục trên (k1, k2, ...). Thia có thể có lợi cho quét phạm vi (chỉ mục có thể được sử dụng để tìm kiếm trên c1 + c2 + c3.

Tất nhiên, tất cả các +hoạt động trong ví dụ của tôi là tập hợp chuỗi, toán tử thực tế sử dụng phụ thuộc vào loại của tất cả các cột đó (tức là bạn có thể phải sử dụng các biểu mẫu rõ ràng).

Tái bút Vì các ràng buộc duy nhất được thi hành bởi một chỉ mục duy nhất, mọi hạn chế đối với các chỉ mục duy nhất cũng sẽ được áp dụng cho các ràng buộc duy nhất:

create table t (
    c1 char(3), c2 char(3), c3 char(3), c4 char(3),
    c5 char(3), c6 char(3), c7 char(3), c8 char(3),
    c9 char(3), c10 char(3), c11 char(3), c12 char(3),
    c13 char(3), c14 char(3), c15 char(3), c16 char(3),
    c17 char(3), c18 char(3), c19 char(3), c20 char(3),
    constraint unq unique
      (c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18));
go  


Msg 1904, Level 16, State 1, Line 3
The index '' on table 't' has 18 column names in index key list. 
The maximum limit for index or statistics key column list is 16.
Msg 1750, Level 16, State 0, Line 3
Could not create constraint. See previous errors.

Tuy nhiên, việc tạo ra các ràng buộc trên một cột được tính toán bền vững:

create table t (
    c1 char(3), c2 char(3), c3 char(3), c4 char(3),
    c5 char(3), c6 char(3), c7 char(3), c8 char(3),
    c9 char(3), c10 char(3), c11 char(3), c12 char(3),
    c13 char(3), c14 char(3), c15 char(3), c16 char(3),
    c17 char(3), c18 char(3), c19 char(3), c20 char(3),
    all_c as 
        c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11+
        c12+c13+c14+c15+c16+c17+c18 
        persisted
        constraint unq unique (all_c));
go  

Rõ ràng, cột bền bỉ tiêu tốn dung lượng trên đĩa nên cách tiếp cận có thể không tốt cho một bảng rất lớn. Cách tiếp cận khung nhìn được lập chỉ mục không có vấn đề này, nó chỉ tiêu tốn không gian cho chỉ mục , không phải không gian cho cột chỉ mục được tính toán .


1
Theo dõi giới hạn khóa chỉ mục 900 byte tất nhiên ...
gbn

1
@gbn Vâng, và đó là lý do tại sao tôi kết thúc với chức năng HashBytes theo đề xuất của RBarryYoung. Tuy nhiên, tôi đã chấp nhận câu trả lời này vì nó cung cấp nhiều giải thích và khám phá các phương pháp khác nhau. (tức là tôi đã học được rất nhiều ở đây)
Nick B

13

Tôi nghĩ rằng bạn sẽ làm tốt hơn nhiều khi đặt kiểm tra chỉ mục duy nhất của bạn trên một cột được tính toán được tạo bằng cách sử dụng HASHBYTES('MD5', ...)kết hợp 18 cột của bạn.


2

Tôi gặp phải vấn đề này và DBA cấp cao của tôi đề nghị sử dụng chức năng kiểm tra tính duy nhất. Các phần chèn của tôi tương đối nhỏ và không thường xuyên (~ 1000 hàng, được chèn vào đầu mỗi tháng) và mối quan tâm duy nhất của tôi là thực thi tính duy nhất.

CREATE FUNCTION dbo.fn_UQ_table1 ()  
RETURNS BIT

AS
BEGIN
      DECLARE @ResultBit BIT = 1

      IF EXISTS(
      SELECT COUNT(*)
      FROM [table1]
      GROUP BY [c1],[c2],[c3],[c4],[c5],[c6],
            [c7],[c8],[c9],[c10],[c11],[c12],
            [c13],[c14],[c15],[c16]
      HAVING COUNT(*) > 1)
      SELECT @ResultBit = 0

      RETURN      @ResultBit

END

SELECT dbo.fn_UQ_table1()

ALTER TABLE [table1]  
WITH NOCHECK ADD  
CONSTRAINT [CK_UQ] CHECK  (([dbo].[fn_UQ_table1]()=1))

@RBarryYoung, tôi chưa có đại diện để bình luận, nhưng tôi gặp rắc rối với giải pháp HASHBYTES vì một trong các loại dữ liệu của tôi là datetime và tôi đã phạm phải lỗi người mới (?) Không cung cấp đối số kiểu tùy chọn cho tôi Hàm CHUYỂN ĐỔI khi chuyển đổi sang varchar. Không có kiểu dáng, bạn sẽ gặp lỗi sau khi bạn cố gắng thêm các PERSISTED UNIQUE NONCLUSTEREDràng buộc:

"column 'key_hash' in table 'table1' cannot be persisted because 
the column is non-deterministic."

0

Bạn có thể kết hợp một số giá trị để tạo một giá trị duy nhất mới và lưu trữ ngoài dữ liệu hiện tại.

Tạo một hàm do người dùng xác định để tạo các giá trị mới và kích hoạt để điền vào trường khi dữ liệu được thêm vào, khi đó bạn không có nhiều chi phí hơn trong việc duy trì trường.

Kết hợp hai hoặc ba lĩnh vực của bạn sẽ giúp bạn dưới giới hạn 16.


-1 Tôi không đồng ý với ý tưởng không chuẩn hóa bảng vì mục đích giảm số lượng cột.
Matt M

@Matt M - Tôi muốn biết lý do tại sao bạn bỏ phiếu cho câu trả lời của tôi khi nó không quá khác biệt so với đề xuất đầu tiên trong câu trả lời được chấp nhận cho câu hỏi này? Tôi cũng muốn biết tại sao bạn không đồng ý, giải pháp của bạn là gì?
Tony

Trên thực tế, đề xuất của bạn, trên thực tế, khác với giải pháp được chấp nhận. Bạn đang ủng hộ việc kết hợp các cột, trong khi giải pháp được chấp nhận đang ủng hộ việc tạo một cột mới có chứa các giá trị kết hợp. Giải pháp của bạn có khả năng có thể trình bày các vấn đề về hiệu suất thông qua các truy vấn quá phức tạp để phân tách dữ liệu hữu ích ra khỏi các cột kết hợp của bạn. Cá nhân, tôi sẽ ủng hộ giải pháp được trình bày bởi RBarryYoung sử dụng cột được tính toán kết hợp HashBytes PERSISTED được đặt vào một chỉ mục duy nhất. Ngược lại, tôi nêu lên giải pháp của anh ấy.
Matt M

@Matt M - Cảm ơn lời giải thích của bạn nhưng tôi đã nói "... tạo ra một giá trị duy nhất mới và lưu trữ ngoài dữ liệu hiện tại." Tôi dự định cột khóa mới là một trường mới bổ sung cho dữ liệu hiện có và không thay thế nó. Tôi đồng ý việc sử dụng trường được tính toán bền bỉ tốt hơn đề xuất của tôi về UDF nhưng về tinh thần, giải pháp của tôi là như vậy.
Tony

Có vẻ như tôi đã đọc sai giải pháp của bạn và tôi xin lỗi vì điều đó. Điều đó đã được nói, kết hợp một vài trong số các cột không phải là một giải pháp tốt, theo ý kiến ​​của tôi, như giải pháp HashBytes đưa ra. Tôi sẽ rút lại -1. Một lần nữa, tôi xin lỗi vì đã đọc hiểu.
Matt M

0

Bạn có thể đi với một kích hoạt cho insert/ update. Thực hiện chọn nhóm theo các cột của bạn với một mệnh đề having count(*) > 1. Nếu điều đó trở lại không trống, cuộn lại.


0

Đây là những gì tôi sẽ làm. Tôi sẽ tạo một trình kích hoạt SAU cho CHERTN, CẬP NHẬT có ROW_NUMBER ()chức năng và phân vùng theo tất cả 18 cột duy nhất của bạn. Nếu số hàng tối đa lớn hơn một, thì làm a ROLLBACK.

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.