インデックスのキー列として使用するには無効なタイプです


180

私はエラーがあります

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

ここで、keyはnvarchar(max)です。簡単なグーグルはこれを見つけました。ただし、ソリューションが何であるかは説明していません。キーと値の両方が文字列であり、明らかにキーが一意であり、単一である、Dictionaryのようなものをどのように作成しますか?私のSQLステートメントは

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

16
(潜在的に)4GB大きくてユニークなキーが本当に必要ですか?一意性のチェックは非常に時間がかかる操作なる可能性があるため、SqlServerはこれを許可しません。
クラウスビスコフペデルセン

@KlausByskovPedersen PostgreSQLのようないくつかのより強力なDBMSは、それを可能にし、代わりにダイジェストにインデックスを付けるのに十分スマートです。しかし、あなたはポイントを持っています。
Matthieu

回答:


244

一意の制約は1行あたり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)OR を使用するスペースがありますnvarchar(450)
Daniel Renshaw、

私の理解では、varcharは項目の長さを決定するために4バイトを必要とするため、実際の制限はvarchar(896)である必要があります。これは正しいです?
mrmillsy

2
@mrmillsy宣言された最大サイズにはオーバーヘッド(4ではなく2バイト)は含まれず、オーバーヘッドバイトは最大インデックス行サイズの制限に含まれません。technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw

1
@mrmillsyをID1 intインデックスに含めているため、このメッセージが表示されます。これにintは、の900バイトに加えて、4バイトが必要varcharです。
Daniel Renshaw 2014年

33

SQL Server(2008 R2まで)には、varchar(MAX)およびnvarchar(MAX)(およびtext、ntextなどの他のいくつかのタイプ)をインデックスで使用できないという制限があります。次の2つのオプションがあります
。1.キーフィールドexに制限されたサイズを設定します。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

ただし、ネイティブインデックスはチェック制約よりもパフォーマンスが高いため、実際に長さを指定できない場合を除いて、チェック制約を使用しないでください。


賢い-トリガーよりもいいと思う。
Neil Moss

14

唯一の解決策は、一意のインデックスで使用するデータを減らすことです。キーは最大でNVARCHAR(450)にすることができます。

「SQL Serverは、すべてのインデックスキー列の最大合計サイズの900バイトの制限を保持しています。」

MSDNで詳細を読む


varcharの場合、制限はvarchar(450)のままですか?
Steam


2

キーの長さがギガバイトである必要があるというklaisbyskovのコメントに注意してください。実際にこれが必要だとすると、選択肢は次のとおりです。

  1. キー値のハッシュを使用する
    • nchar(40)に列を作成します(たとえば、sha1ハッシュの場合)。
    • ハッシュ列に一意のキーを置きます。
    • レコードを保存または更新するときにハッシュを生成する
  2. トリガーは、挿入または更新時に既存の一致についてテーブルを照会します。

ハッシュには、衝突が発生する可能性があるという警告が伴います。

トリガーはテーブル全体をスキャンします。

あなたに...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.