є неприпустимим для використання в якості ключового стовпчика в індексі


180

У мене помилка в

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

де ключ - nvarchar (max). Швидкий Google знайшов це . Однак це не пояснює, що таке рішення. Як я можу створити щось на зразок словника, де ключ і значення є обома рядками, і очевидно, що ключ повинен бути унікальним і єдиним. Моя заява sql була

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
Що стосується варчара, чи все ще обмеженням буде варчар (450)?
Паровий

9
У вас є місце для використання varchar(900)АБО АБО nvarchar(450).
Даніель Реншо

Я розумію, що варчар візьме 4 байти, щоб визначити довжину елемента, тобто фактичний межа повинен бути варчаром (896). Це правильно?
mrmillsy

2
@mrmillsy Заявлений максимальний розмір не включає накладні витрати (що становить 2 байти, а не 4), а байти накладних даних не включаються в обмеження максимального розміру рядка індексу. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw

1
@mrmillsy Ви отримуєте це повідомлення, оскільки ви включаєте ID1 intв індекс. Для цього intпотрібно 4 байти, крім 900 байт для varchar.
Даніель Реншо

33

У SQL Server (до 2008 R2) існує обмеження, що varchar (MAX) та nvarchar (MAX) (та кілька інших типів, таких як текст, 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


Що стосується варчара, чи все ще обмеженням буде варчар (450)?
Пар


2

Помічаючи коментар klaisbyskov про вашу довжину ключа, яка повинна бути розміром гігабайт, і припускаючи, що ви насправді цього потребуєте, я думаю, що ваші єдині варіанти:

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

Хешинг приходить із застереженням, що одного дня, ти може виникнути зіткнення.

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

До вас...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.