【问题标题】:is of a type that is invalid for use as a key column in an index是在索引中用作键列无效的类型
【发布时间】:2011-02-21 06:46:12
【问题描述】:

我有一个错误

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)。快速谷歌搜索发现索引的最大长度为 450 个字符。但是,这并不能解释什么是解决方案。我如何创建像 Dictionary 这样的键和值都是字符串并且显然键必须是唯一的并且是单一的?我的sql语句是

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

【问题讨论】:

  • 您真的需要(可能)4GB 大且独一无二的密钥吗? SqlServer 不允许这样做,因为检查唯一性可能是一个非常耗时的操作。
  • @KlausByskovPedersen 一些更强大的 DBMS(如 PostgreSQL)足够聪明,可以允许它使用并索引摘要。但你说得有道理。
  • 限制 varchar 长度是否可行
  • 如果您使用的是代码优先的实体框架,如果您尝试索引字符串类型的变量,则会遇到此错误。

标签: sql sql-server-2008


【解决方案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 个字符。

【讨论】:

  • 对于 varchar,限制仍然是 varchar(450) 吗?
  • 您有空间可以使用varchar(900)nvarchar(450)
  • 我的理解是一个varchar需要4个字节来确定item的长度,也就是说实际的限制需要是varchar(896)。这是正确的吗?
  • @mrmillsy 声明的最大大小不包括开销(这是 2 个字节,而不是 4 个),并且开销字节不包括在最大索引行大小的限制中。 technet.microsoft.com/en-us/library/ms176089(v=sql.100).aspx
  • @mrmillsy 您收到该消息是因为您在索引中包含了ID1 int。除了 varchar 的 900 个字节之外,int 还需要 4 个字节。
【解决方案2】:

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

但请注意,本机索引比检查约束更高效,因此除非您确实无法指定长度,否则不要使用检查约束。

【讨论】:

  • 聪明 - 我觉得比触发器更好。
【解决方案3】:

注意到 klaisbyskov 关于您的密钥长度需要千兆字节大小的评论,并假设您确实需要这个,那么我认为您唯一的选择是:

  1. 使用键值的散列
    • 在 nchar(40) 上创建一列(例如,用于 sha1 哈希),
    • 在哈希列上放置一个唯一键。
    • 保存或更新记录时生成哈希
  2. 触发器在插入或更新时查询表以查找现有匹配项。

哈希伴随着警告,有一天,您可能会发生冲突。

触发器将扫描整个表。

交给你...

【讨论】:

    【解决方案4】:

    唯一的解决方案是在唯一索引中使用更少的数据。您的密钥最多可以是 NVARCHAR(450)。

    “SQL Server 保留所有索引键列的最大总大小限制为 900 字节。”

    阅读更多MSDN

    【讨论】:

    • 对于 varchar,限制仍然是 varchar(450) 吗?
    【解决方案5】:

    一种解决方案是将您的密钥声明为nvarchar(20)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 2013-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      相关资源
      最近更新 更多