имеет недопустимый тип для использования в качестве ключевого столбца в индексе

180

У меня ошибка в

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

где ключ - это nvarchar (макс.) Быстрый Google нашел это . Однако это не объясняет, что такое решение. Как мне создать что-то вроде словаря, в котором ключ и значение являются строками и, очевидно, ключ должен быть уникальным и единственным. Мое заявление было

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

источник
16
Вы действительно нуждаетесь в том, чтобы ваш ключ был (потенциально) 4 ГБ большим И уникальным? SqlServer не позволяет этого, потому что проверка уникальности может быть очень трудоемкой операцией.
Клаус Бысков Педерсен
@KlausByskovPedersen некоторые более мощные СУБД, такие как PostgreSQL, достаточно умны, чтобы позволить это и вместо этого индексировать дайджест. Но у тебя есть смысл.
Матье

Ответы:

244

Уникальное ограничение не может превышать 8000 байт на строку, и даже тогда будут использоваться только первые 900 байт, поэтому максимальный максимальный размер для ваших ключей будет:

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

т.е. ключ не может быть более 450 символов. Если вы можете переключиться на varcharвместо nvarchar(например, если вам не нужно хранить символы из более чем одной кодовой страницы), это может увеличиться до 900 символов.

Даниэль Реншоу
источник
1
Будет ли предел для varchar varchar (450)?
Steam
9
У вас есть место, чтобы использовать либо varchar(900)ИЛИ nvarchar(450).
Даниэль Реншоу
Насколько я понимаю, для определения длины элемента varchar потребуется 4 байта, то есть фактический предел должен быть varchar (896). Это верно?
mrmillsy
2
@mrmillsy Объявленный максимальный размер не включает служебные данные (то есть 2 байта, а не 4), а служебные байты не включены в ограничение на максимальный размер строки индекса. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Даниэль Реншоу
1
@mrmillsy Вы получаете это сообщение, потому что включаете ID1 intв индекс. Это intтребует 4 байта, в дополнение к 900 байтов для varchar.
Даниэль Реншоу
33

В SQL Server есть ограничение (до 2008 R2), что varchar (MAX) и nvarchar (MAX) (и некоторые другие типы, такие как text, ntext) не могут использоваться в индексах. У вас есть 2 варианта:
1. Установить ограниченный размер в ключевом поле напр. nvarchar (100)
2. Создайте проверочное ограничение, которое сравнивает значение со всеми ключами в таблице. Состояние:

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

и [dbo]. [CheckKey] является скалярной функцией, определенной как:

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

Но обратите внимание, что собственный индекс является более производительным, чем проверочное ограничение, поэтому, если вы действительно не можете указать длину, не используйте проверочное ограничение.

Марван
источник
Я чувствую, умнее, чем триггеры.
Нил Мосс
14

Единственное решение - использовать меньше данных в вашем уникальном индексе. Ваш ключ может быть NVARCHAR (450) максимум.

«SQL Server сохраняет ограничение в 900 байт для максимального общего размера всех столбцов ключа индекса».

Узнайте больше на MSDN

Дон
источник
Будет ли предел для varchar varchar (450)?
Steam
7

Решением было бы объявить ваш ключ как nvarchar(20).

Клаус Бысков Педерсен
источник
2

Если принять во внимание комментарий Клайсбыскова о том, что длина ключа должна быть в гигабайтах, и предположить, что вам это действительно нужно, то я думаю, что единственные варианты:

  1. использовать хеш значения ключа
    • Создайте столбец в nchar (40) (например, для хэша sha1),
    • поместите уникальный ключ в столбец хеша.
    • генерировать хеш при сохранении или обновлении записи
  2. триггеры для запроса таблицы на существующее совпадение при вставке или обновлении.

Хеширование сопровождается оговоркой, что однажды вы можете столкнуться.

Триггеры будут сканировать всю таблицу.

К вам ...

Нил Мосс
источник