adalah tipe yang tidak valid untuk digunakan sebagai kolom kunci dalam indeks

180

Saya memiliki kesalahan di

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

di mana kuncinya adalah nvarchar (maks). Google cepat menemukan ini . Namun itu tidak menjelaskan apa solusinya. Bagaimana cara membuat sesuatu seperti Kamus di mana kunci dan nilainya adalah string dan jelas kuncinya harus unik dan tunggal. Pernyataan sql saya adalah

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

sumber
16
Apakah Anda benar-benar membutuhkan kunci Anda (berpotensi) 4GB besar DAN unik? SqlServer tidak mengizinkan ini karena memeriksa keunikan berpotensi menjadi operasi yang sangat memakan waktu.
Klaus Byskov Pedersen
@KlausByskovPedersen beberapa DBMS yang lebih kuat seperti PostgreSQL cukup pintar untuk memungkinkan dan mengindeks intisari sebuah gantinya. Tapi Anda ada benarnya.
Matthieu

Jawaban:

244

Batasan unik tidak boleh lebih dari 8000 byte per baris dan hanya akan menggunakan 900 byte pertama, jadi ukuran maksimum teraman untuk kunci Anda adalah:

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

yaitu kuncinya tidak boleh lebih dari 450 karakter. Jika Anda dapat beralih ke varcharalih-alih nvarchar(mis. Jika Anda tidak perlu menyimpan karakter dari lebih dari satu codepage) maka itu dapat meningkat menjadi 900 karakter.

Daniel Renshaw
sumber
1
Untuk varchar, apakah batasnya masih varchar (450)?
Steam
9
Anda memiliki ruang untuk menggunakan varchar(900)OR nvarchar(450).
Daniel Renshaw
Pemahaman saya adalah bahwa varchar akan mengambil 4 byte untuk menentukan panjang item, artinya batas sebenarnya harus varchar (896). Apakah ini benar?
mrmillsy
2
@ mrmillsy Ukuran maksimum yang dideklarasikan tidak termasuk overhead (yaitu 2 byte, bukan 4) dan byte overhead tidak termasuk dalam batas ukuran baris indeks maksimum. technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
Daniel Renshaw
1
@ mrmillsy Anda menerima pesan itu karena Anda termasuk ID1 intdalam indeks. Itu intmembutuhkan 4 byte, selain 900 byte untuk varchar.
Daniel Renshaw
33

Ada batasan dalam SQL Server (hingga 2008 R2) bahwa varchar (MAX) dan nvarchar (MAX) (dan beberapa jenis lain seperti teks, ntext) tidak dapat digunakan dalam indeks. Anda memiliki 2 opsi:
1. Tetapkan ukuran terbatas pada bidang kunci, mis. nvarchar (100)
2. Buat batasan pemeriksaan yang membandingkan nilai dengan semua kunci di tabel. Syaratnya adalah:

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

dan [dbo]. [CheckKey] adalah fungsi skalar yang didefinisikan sebagai:

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

Tetapi perhatikan bahwa indeks asli lebih berkinerja daripada kendala pemeriksaan jadi kecuali Anda benar-benar tidak dapat menentukan panjang, jangan gunakan kendala periksa.

Marwan
sumber
Saya pandai - lebih bagus daripada pemicu.
Neil Moss
14

Satu-satunya solusi adalah dengan menggunakan lebih sedikit data dalam Indeks Unik Anda. Kunci Anda paling banyak NVARCHAR (450).

"SQL Server mempertahankan batas 900-byte untuk ukuran total maksimum semua kolom kunci indeks."

Baca lebih lanjut di MSDN

Mengenakan
sumber
Untuk varchar, apakah batasnya masih varchar (450)?
Steam
7

Sebuah solusi akan menyatakan kunci Anda sebagai nvarchar(20).

Klaus Byskov Pedersen
sumber
2

Memperhatikan komentar klaisbyskov tentang panjang kunci Anda harus berukuran gigabytes, dan dengan asumsi bahwa Anda memang membutuhkannya, maka saya pikir satu-satunya pilihan Anda adalah:

  1. gunakan hash dari nilai kunci
    • Buat kolom di nchar (40) (untuk hash sha1, misalnya),
    • letakkan kunci unik di kolom hash.
    • menghasilkan hash saat menyimpan atau memperbarui catatan
  2. pemicu untuk menanyakan tabel untuk kecocokan yang ada saat disisipkan atau diperbarui.

Hashing datang dengan peringatan bahwa suatu hari, Anda mungkin mendapatkan tabrakan.

Pemicu akan memindai seluruh tabel.

Ke Anda...

Neil Moss
sumber