è di un tipo non valido per l'uso come colonna chiave in un indice


180

Ho un errore a

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

dove key è un nvarchar (max). Un rapido google ha trovato questo . Tuttavia non spiega quale sia una soluzione. Come faccio a creare qualcosa come Dictionary in cui la chiave e il valore sono entrambi stringhe e ovviamente la chiave deve essere unica ed è singola. La mia dichiarazione sql era

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

16
Hai davvero bisogno che la tua chiave sia (potenzialmente) larga 4 GB E unica? SqlServer non lo consente perché il controllo dell'unicità potrebbe potenzialmente essere un'operazione che richiede molto tempo.
Klaus Byskov Pedersen,

@KlausByskovPedersen alcuni DBMS più potenti come PostgreSQL sono abbastanza intelligenti da permetterlo e indicizzare invece un digest. Ma hai ragione.
Matthieu,

Risposte:


244

Un vincolo univoco non può essere superiore a 8000 byte per riga e utilizzerà solo i primi 900 byte anche in questo caso, quindi la dimensione massima più sicura per le chiavi sarebbe:

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

cioè la chiave non può contenere più di 450 caratteri. Se è possibile passare a varcharanziché nvarchar(ad esempio se non è necessario memorizzare caratteri da più di una tabella codici), ciò potrebbe aumentare a 900 caratteri.


1
Per varchar, il limite sarebbe ancora varchar (450)?
Steam,

9
Hai spazio per utilizzare varchar(900)OR nvarchar(450).
Daniel Renshaw,

La mia comprensione è che un varchar impiegherà 4 byte per determinare la lunghezza dell'articolo, il che significa che il limite effettivo deve essere varchar (896). È corretto?
mrmillsy,

2
@mrmillsy La dimensione massima dichiarata non include l'overhead (che è 2 byte, non 4) e i byte overhead non sono inclusi nel limite sulla dimensione massima della riga dell'indice. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw,

1
@mrmillsy Ricevi questo messaggio perché includi ID1 intl'indice. Ciò intrichiede 4 byte, oltre ai 900 byte per il varchar.
Daniel Renshaw,

33

Esiste una limitazione in SQL Server (fino al 2008 R2) che varchar (MAX) e nvarchar (MAX) (e molti altri tipi come text, ntext) non possono essere utilizzati negli indici. Sono disponibili 2 opzioni:
1. Impostare una dimensione limitata sul campo chiave es. nvarchar (100)
2. Creare un vincolo di controllo che confronta il valore con tutte le chiavi nella tabella. La condizione è:

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

e [dbo]. [CheckKey] è una funzione scalare definita come:

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

Tuttavia, tieni presente che un indice nativo è più performante di un vincolo di controllo, quindi a meno che non sia possibile specificare una lunghezza, non utilizzare il vincolo di controllo.


Intelligente - più bello dei grilletti, mi sento.
Neil Moss,

14

L'unica soluzione è utilizzare meno dati nel tuo indice univoco. La chiave può essere al massimo NVARCHAR (450).

"SQL Server mantiene il limite di 900 byte per la dimensione totale massima di tutte le colonne chiave dell'indice."

Maggiori informazioni su MSDN


Per varchar, il limite sarebbe ancora varchar (450)?
Steam,


2

Notando il commento di klaisbyskov sulla lunghezza della chiave che deve essere di dimensioni gigabyte, e supponendo che in realtà tu ne abbia bisogno, allora penso che le tue uniche opzioni siano:

  1. usa un hash del valore chiave
    • Crea una colonna su nchar (40) (ad esempio per un hash sha1),
    • inserisci una chiave univoca nella colonna hash.
    • genera l'hash durante il salvataggio o l'aggiornamento del record
  2. innesca per interrogare la tabella per una corrispondenza esistente su insert o update.

L'hashing arriva con l'avvertenza che un giorno potresti avere una collisione.

I trigger eseguiranno la scansione dell'intera tabella.

A voi...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.