est d'un type non valide pour une utilisation comme colonne clé dans un index

180

J'ai une erreur à

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

où key est un nvarchar (max). Un google rapide a trouvé ceci . Il n'explique cependant pas ce qu'est une solution. Comment puis-je créer quelque chose comme Dictionary où la clé et la valeur sont toutes deux des chaînes et, de toute évidence, la clé doit être unique et unique. Ma déclaration SQL était

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

la source
16
Avez-vous vraiment besoin que votre clé soit (potentiellement) de 4 Go de large ET unique? SqlServer ne permet pas cela car la vérification de l'unicité pourrait potentiellement être une opération très longue.
Klaus Byskov Pedersen
@KlausByskovPedersen, un SGBD plus puissant comme PostgreSQL est suffisamment intelligent pour le permettre et indexer un condensé à la place. Mais vous avez un point.
Matthieu

Réponses:

244

Une contrainte unique ne peut pas dépasser 8000 octets par ligne et n'utilisera que les 900 premiers octets, même alors, la taille maximale la plus sûre pour vos clés serait:

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

c'est-à-dire que la clé ne peut pas dépasser 450 caractères. Si vous pouvez passer à varcharau lieu de nvarchar(par exemple, si vous n'avez pas besoin de stocker des caractères de plus d'une page de codes), cela pourrait augmenter à 900 caractères.

Daniel Renshaw
la source
1
Pour varchar, la limite serait-elle toujours varchar (450)?
Steam
9
Vous avez de l'espace pour utiliser varchar(900)OU nvarchar(450).
Daniel Renshaw
Je crois comprendre qu'un varchar prendra 4 octets pour déterminer la longueur de l'élément, ce qui signifie que la limite réelle doit être varchar (896). Est-ce correct?
mrmillsy
2
@mrmillsy La taille maximale déclarée n'inclut pas la surcharge (qui est de 2 octets, pas 4) et les octets de surcharge ne sont pas inclus dans la limite de la taille de ligne d'index maximale. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw
1
@mrmillsy Vous recevez ce message parce que vous incluez le ID1 intdans l'index. Cela intnécessite 4 octets, en plus des 900 octets pour le varchar.
Daniel Renshaw
33

Il existe une limitation dans SQL Server (jusqu'en 2008 R2) selon laquelle varchar (MAX) et nvarchar (MAX) (et plusieurs autres types comme le texte, ntext) ne peuvent pas être utilisés dans les index. Vous avez 2 options:
1. Définissez une taille limitée sur le champ clé ex. nvarchar (100)
2. Créez une contrainte de vérification qui compare la valeur à toutes les clés de la table. La condition est:

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

et [dbo]. [CheckKey] est une fonction scalaire définie comme:

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

Mais notez qu'un index natif est plus performant qu'une contrainte de vérification, donc à moins que vous ne puissiez vraiment spécifier une longueur, n'utilisez pas la contrainte de vérification.

Marwan
la source
Intelligent - plus agréable que les déclencheurs, je pense.
Neil Moss
14

La seule solution consiste à utiliser moins de données dans votre index unique. Votre clé peut être NVARCHAR (450) au maximum.

"SQL Server conserve la limite de 900 octets pour la taille totale maximale de toutes les colonnes de clé d'index."

En savoir plus sur MSDN

Don
la source
Pour varchar, la limite serait-elle toujours varchar (450)?
Steam
7

Une solution serait de déclarer votre clé comme nvarchar(20).

Klaus Byskov Pedersen
la source
2

En notant le commentaire de klaisbyskov sur la longueur de votre clé devant être de gigaoctets, et en supposant que vous en avez réellement besoin, alors je pense que vos seules options sont:

  1. utiliser un hachage de la valeur de clé
    • Créer une colonne sur nchar (40) (pour un hachage sha1, par exemple),
    • mettez une clé unique sur la colonne de hachage.
    • générer le hachage lors de la sauvegarde ou de la mise à jour de l'enregistrement
  2. déclencheurs pour interroger la table pour une correspondance existante lors de l'insertion ou de la mise à jour.

Le hachage vient avec l'avertissement qu'un jour, vous pourriez avoir une collision.

Les déclencheurs analyseront la table entière.

À vous ...

Neil Moss
la source