là loại không hợp lệ để sử dụng làm cột chính trong chỉ mục


180

Tôi có một lỗi tại

Column 'key' in table 'misc_info' is of a type that is invalid for use as a key column in an index.

trong đó khóa là một nvarchar (max). Một google nhanh chóng tìm thấy điều này . Tuy nhiên nó không giải thích một giải pháp là gì. Làm thế nào để tôi tạo một cái gì đó như Từ điển trong đó khóa và giá trị là cả hai chuỗi và rõ ràng khóa phải là duy nhất và là duy nhất. Tuyên bố sql của tôi là

create table [misc_info] (
[id] INTEGER PRIMARY KEY IDENTITY NOT NULL,
[key] nvarchar(max) UNIQUE NOT NULL,
[value] nvarchar(max) NOT NULL);

16
Bạn có thực sự cần chìa khóa của mình để trở thành (lớn) 4GB lớn và duy nhất không? SQLServer không cho phép điều này bởi vì kiểm tra tính độc đáo có khả năng có thể là một rất tốn thời gian hoạt động.
Klaus Byskov Pedersen

@KlausByskovPedersen một số DBMS mạnh hơn như PostgreSQL đủ thông minh để cho phép nó và lập chỉ mục một bản tóm tắt thay thế. Nhưng bạn có một điểm.
Matthieu

Câu trả lời:


244

Một ràng buộc duy nhất không thể vượt quá 8000 byte mỗi hàng và sẽ chỉ sử dụng 900 byte đầu tiên ngay cả khi đó kích thước tối đa an toàn nhất cho các khóa của bạn sẽ là:

create table [misc_info]
( 
    [id] INTEGER PRIMARY KEY IDENTITY NOT NULL, 
    [key] nvarchar(450) UNIQUE NOT NULL, 
    [value] nvarchar(max) NOT NULL
)

tức là khóa không thể có hơn 450 ký tự. Nếu bạn có thể chuyển sang varcharthay vì nvarchar(ví dụ: nếu bạn không cần lưu trữ các ký tự từ nhiều hơn một bảng mã) thì có thể tăng lên 900 ký tự.


1
Đối với varchar, giới hạn vẫn là varchar (450)?
Hơi nước

9
Bạn có không gian để sử dụng varchar(900)HOẶC nvarchar(450).
Daniel Renshaw

Sự hiểu biết của tôi là một varchar sẽ mất 4 byte để xác định độ dài của mục, nghĩa là giới hạn thực tế cần phải là varchar (896). Điều này có đúng không?
mrmillsy

2
@mrmillsy Kích thước tối đa được khai báo không bao gồm tổng phí (là 2 byte, không phải 4) và các byte trên không được bao gồm trong giới hạn về kích thước hàng chỉ mục tối đa. technet.microsoft.com/en-us/l Library / ms176089 (v = sql.100) .aspx
Daniel Renshaw

1
@mrmillsy Bạn nhận được thông báo đó vì bạn đang bao gồm ID1 inttrong chỉ mục. Điều đó intđòi hỏi 4 byte, ngoài 900 byte cho varchar.
Daniel Renshaw

33

Có một hạn chế trong SQL Server (cho đến 2008 R2) rằng varchar (MAX) và nvarchar (MAX) (và một số loại khác như văn bản, ntext) không thể được sử dụng trong các chỉ mục. Bạn có 2 tùy chọn:
1. Đặt kích thước giới hạn trên trường khóa cũ. nvarchar (100)
2. Tạo một ràng buộc kiểm tra so sánh giá trị với tất cả các khóa trong bảng. Điều kiện là:

([dbo].[CheckKey]([key])=(1))

và [dbo]. [CheckKey] là một hàm vô hướng được định nghĩa là:

CREATE FUNCTION [dbo].[CheckKey]
(
    @key nvarchar(max)
)
RETURNS bit
AS
BEGIN
    declare @res bit
    if exists(select * from key_value where [key] = @key)
        set @res = 0
    else
        set @res = 1

    return @res
END

Nhưng lưu ý rằng một chỉ mục gốc có hiệu suất cao hơn ràng buộc kiểm tra vì vậy trừ khi bạn thực sự không thể chỉ định độ dài, đừng sử dụng ràng buộc kiểm tra.


Thông minh - đẹp hơn kích hoạt, tôi cảm thấy.
Neil Moss

14

Giải pháp duy nhất là sử dụng ít dữ liệu hơn trong Chỉ mục duy nhất của bạn. Khóa của bạn có thể là NVARCHAR (450) tối đa.

"SQL Server duy trì giới hạn 900 byte cho tổng kích thước tối đa của tất cả các cột khóa chỉ mục."

Đọc thêm tại MSDN


Đối với varchar, giới hạn vẫn là varchar (450)?
Hơi nước


2

Lưu ý nhận xét của klaisbyskov về độ dài khóa của bạn cần có kích thước gigabyte và giả sử rằng bạn thực sự cần điều này, thì tôi nghĩ các lựa chọn duy nhất của bạn là:

  1. sử dụng hàm băm của giá trị khóa
    • Tạo một cột trên nchar (40) (ví dụ cho hàm băm sha1),
    • đặt một khóa duy nhất trên cột băm.
    • tạo hàm băm khi lưu hoặc cập nhật bản ghi
  2. kích hoạt để truy vấn bảng cho một trận đấu hiện có khi chèn hoặc cập nhật.

Băm đi kèm với lời cảnh báo rằng một ngày nào đó, bạn có thể bị va chạm.

Triggers sẽ quét toàn bộ bảng.

Về với bạn ...

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.