es de un tipo que no es válido para su uso como columna clave en un índice

180

Tengo un error en

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

donde key es un nvarchar (max). Un google rápido encontró esto . Sin embargo, no explica qué es una solución. ¿Cómo creo algo como Diccionario donde la clave y el valor son cadenas y obviamente la clave debe ser única y única? Mi declaración SQL fue

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

fuente
16
¿Realmente necesita que su clave sea (potencialmente) de 4GB grande Y única? SqlServer no permite esto porque verificar la unicidad podría ser una operación que requiere mucho tiempo.
Klaus Byskov Pedersen
@KlausByskovPedersen algunos DBMS más potentes como PostgreSQL son lo suficientemente inteligentes como para permitirlo e indexar un resumen en su lugar. Pero tienes un punto.
Matthieu

Respuestas:

244

Una restricción única no puede superar los 8000 bytes por fila y solo utilizará los primeros 900 bytes, incluso así, el tamaño máximo más seguro para sus claves sería:

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

es decir, la clave no puede tener más de 450 caracteres. Si puede cambiar a en varcharlugar de nvarchar(por ejemplo, si no necesita almacenar caracteres de más de una página de códigos), eso podría aumentar a 900 caracteres.

Daniel Renshaw
fuente
1
Para varchar, ¿el límite seguiría siendo varchar (450)?
Steam
9
Tiene espacio para usar varchar(900)OR nvarchar(450).
Daniel Renshaw
Tengo entendido que un varchar tomará 4 bytes para determinar la longitud del elemento, lo que significa que el límite real debe ser varchar (896). ¿Es esto correcto?
mrmillsy
2
@mrmillsy El tamaño máximo declarado no incluye la sobrecarga (que es 2 bytes, no 4) y los bytes de sobrecarga no están incluidos en el límite del tamaño máximo de fila de índice. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw
1
@mrmillsy Recibes ese mensaje porque estás incluyendo el ID1 inten el índice. Eso intrequiere 4 bytes, además de los 900 bytes para el varchar.
Daniel Renshaw
33

Existe una limitación en SQL Server (hasta 2008 R2) que varchar (MAX) y nvarchar (MAX) (y varios otros tipos como text, ntext) no pueden usarse en índices. Tiene 2 opciones:
1. Establecer un tamaño limitado en el campo clave ej. nvarchar (100)
2. Cree una restricción de verificación que compare el valor con todas las claves de la tabla. La condición es:

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

y [dbo]. [CheckKey] es una función escalar definida como:

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

Pero tenga en cuenta que un índice nativo es más eficaz que una restricción de verificación, por lo que, a menos que realmente no pueda especificar una longitud, no use la restricción de verificación.

Marwan
fuente
Inteligente: mejor que los desencadenantes, creo.
Neil Moss
14

La única solución es usar menos datos en su índice único. Su clave puede ser NVARCHAR (450) como máximo.

"SQL Server retiene el límite de 900 bytes para el tamaño total máximo de todas las columnas de clave de índice".

Más información en MSDN

Don
fuente
Para varchar, ¿el límite seguiría siendo varchar (450)?
Steam
7

Una solución sería declarar su clave como nvarchar(20).

Klaus Byskov Pedersen
fuente
2

Tomando nota del comentario de klaisbyskov sobre la longitud de la clave que debe tener un tamaño de gigabytes, y suponiendo que realmente lo necesite, creo que sus únicas opciones son:

  1. usar un hash del valor clave
    • Cree una columna en nchar (40) (para un hash sha1, por ejemplo),
    • poner una clave única en la columna hash.
    • generar el hash al guardar o actualizar el registro
  2. dispara para consultar en la tabla una coincidencia existente en la inserción o actualización.

Hashing viene con la advertencia de que un día, podría tener una colisión.

Los activadores escanearán toda la tabla.

A ti...

Neil Moss
fuente