jest typu, który jest nieprawidłowy do użycia jako kolumna klucza w indeksie

180

Mam błąd pod adresem

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

gdzie klucz to nvarchar (max). Szybkie Google to znalazło . Nie wyjaśnia jednak, jakie jest rozwiązanie. Jak utworzyć coś takiego jak Dictionary, w którym klucz i wartość są ciągami i oczywiście klucz musi być unikalny i pojedynczy. Moje oświadczenie sql było

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

źródło
16
Czy naprawdę potrzebujesz, aby Twój klucz miał (potencjalnie) 4 GB i był unikalny? SqlServer nie pozwala na to, ponieważ sprawdzanie unikalności może być potencjalnie bardzo czasochłonną operacją.
Klaus Byskov Pedersen
@KlausByskovPedersen niektóre potężniejsze DBMS, takie jak PostgreSQL, są wystarczająco inteligentne, aby zezwolić na to i zamiast tego zindeksować skrót. Ale masz rację.
Matthieu

Odpowiedzi:

244

Unikalne ograniczenie nie może przekraczać 8000 bajtów na wiersz i nawet wtedy będzie używać tylko pierwszych 900 bajtów, więc najbezpieczniejszy maksymalny rozmiar kluczy to:

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

tzn. klucz nie może mieć więcej niż 450 znaków. Jeśli możesz przełączyć się na varcharzamiast nvarchar(np. Jeśli nie musisz przechowywać znaków z więcej niż jednej strony kodowej), może to wzrosnąć do 900 znaków.

Daniel Renshaw
źródło
1
Czy dla varchar limit nadal będzie wynosił varchar (450)?
Steam
9
Masz miejsce na użycie varchar(900)LUB nvarchar(450).
Daniel Renshaw,
Rozumiem, że varchar zajmie 4 bajty, aby określić długość elementu, co oznacza, że ​​rzeczywisty limit musi wynosić varchar (896). Czy to jest poprawne?
mrmillsy
2
@mrmillsy Zadeklarowany maksymalny rozmiar nie obejmuje narzutu (który wynosi 2 bajty, a nie 4), a dodatkowe bajty nie są uwzględnione w limicie maksymalnego rozmiaru wiersza indeksu. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw
1
@mrmillsy Otrzymujesz tę wiadomość, ponieważ umieszczasz ID1 intw indeksie. Że intwymaga 4 bajtów, w uzupełnieniu do 900 bajtów dla varchar.
Daniel Renshaw
33

W SQL Server (do 2008 R2) istnieje ograniczenie, że varchar (MAX) i nvarchar (MAX) (oraz kilka innych typów, takich jak text, ntext) nie mogą być używane w indeksach. Masz 2 opcje:
1. Ustaw ograniczony rozmiar w polu klucza, np. nvarchar (100)
2. Utwórz ograniczenie sprawdzające, które porównuje wartość ze wszystkimi kluczami w tabeli. Warunkiem jest:

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

i [dbo]. [CheckKey] to funkcja skalarna zdefiniowana jako:

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

Pamiętaj jednak, że indeks natywny jest bardziej wydajny niż ograniczenie sprawdzające, więc jeśli naprawdę nie możesz określić długości, nie używaj ograniczenia sprawdzającego.

Marwan
źródło
Sprytne - przyjemniejsze niż wyzwalacze, czuję.
Neil Moss
14

Jedynym rozwiązaniem jest użycie mniejszej ilości danych w unikalnym indeksie. Twój klucz może mieć najwyżej NVARCHAR (450).

„SQL Server zachowuje limit 900 bajtów dla maksymalnego całkowitego rozmiaru wszystkich kolumn klucza indeksu”.

Przeczytaj więcej w MSDN

Don
źródło
Czy dla varchar limit nadal będzie wynosił varchar (450)?
Steam
7

Rozwiązaniem byłoby zadeklarowanie klucza jako nvarchar(20).

Klaus Byskov Pedersen
źródło
2

Zwracając uwagę na komentarz Klaisbyskova, że ​​długość klucza musi wynosić gigabajty, i zakładając, że faktycznie tego potrzebujesz, myślę, że jedyne opcje to:

  1. użyj skrótu wartości klucza
    • Utwórz kolumnę na nchar (40) (na przykład dla skrótu sha1),
    • umieść unikalny klucz w kolumnie hash.
    • generuje skrót podczas zapisywania lub aktualizowania rekordu
  2. wyzwala zapytanie tabeli o istniejące dopasowanie podczas wstawiania lub aktualizacji.

Haszowanie wiąże się z zastrzeżeniem, że pewnego dnia może dojść do kolizji.

Wyzwalacze skanują całą tabelę.

Do Ciebie...

Neil Moss
źródło