Sql server SQL server-值得索引大字符串键吗?

Sql server SQL server-值得索引大字符串键吗?,sql-server,Sql Server,我有一个表,它有一个大的字符串键(varchar(1024)),我想在SQL server上对它进行索引(我希望能够快速搜索它,但插入也很重要)。在sql 2008中,我没有收到任何警告,但在sql server 2005下,它告诉我它超过900字节,并且超过此大小的列的插入/更新将被删除(或该区域中的某些内容) 如果我想在这个大专栏上建立索引,我的备选方案是什么?我不知道如果我可以的话,这是否值得。 当您设计索引时,考虑以下列指南: 对于聚集索引,请保持索引键的长度较短。此外,聚集索引还受益

我有一个表,它有一个大的字符串键(varchar(1024)),我想在SQL server上对它进行索引(我希望能够快速搜索它,但插入也很重要)。在sql 2008中,我没有收到任何警告,但在sql server 2005下,它告诉我它超过900字节,并且超过此大小的列的插入/更新将被删除(或该区域中的某些内容)

如果我想在这个大专栏上建立索引,我的备选方案是什么?我不知道如果我可以的话,这是否值得。

当您设计索引时,考虑以下列指南:

  • 对于聚集索引,请保持索引键的长度较短。此外,聚集索引还受益于在unique上创建 或非空列。有关详细信息,请参见聚集索引设计 准则

  • 不能将ntext、text、image、varchar(max)、nvarchar(max)和varbinary(max)数据类型的列指定为 索引键列。但是,varchar(最大值)、nvarchar(最大值), varbinary(max)和xml数据类型可以参与非聚集 索引为非键索引列。有关详细信息,请参见索引和 包括列

  • 检查列中的数据分布。通常,长时间运行的查询是由索引具有很少唯一值的列或 在这样的列上执行联接。这是一个基本的问题 数据和查询,通常无法在没有 确定这种情况。例如,物理电话 按姓氏字母顺序排序的目录将不可用 如果城市里所有的人都叫史密斯或琼斯,就可以找到一个人


如果索引的所有键都接近900字节,则索引将非常大且非常深(每页很少的键会导致非常高的B树)

这取决于您计划如何查询值。索引在以下几种情况下很有用:

  • 当探测一个值时。这是最典型的用法,即在表中搜索精确值时。典型的例子是
    其中column='ABC'
    或a.column=B.someothercolumn上的连接条件
  • 扫描范围时。当在表中搜索一系列值时,这也是相当典型的。除了“ABC”和“DEF”之间的
    WHERE列的明显示例之外,还有其他不太明显的示例,如部分匹配:
    WHERE列如“ABC%”
  • 订购要求。这种用法不太为人所知,但索引可以帮助具有明确的
    按列排序要求的查询避免停止和进行排序,还可以帮助某些隐藏的排序要求,例如(按列排序)上的
    行编号()
那么,你为什么需要索引呢?什么样的查询会使用它

对于范围扫描和订购需求,除了索引之外没有其他解决方案,您必须权衡索引的成本和好处

对于探测,您可以潜在地使用哈希来避免索引非常大的列。创建一个持久化的计算列作为
column\u checksum=checksum(column)
,然后在该列上建立索引。查询必须重写才能使用
,其中列\u checksum=checksum('ABC')和列='ABC'
。必须仔细考虑窄索引(32位校验和)的优点与碰撞双重检查的缺点以及缺乏范围扫描和顺序功能的缺点之间的权衡

评论之后

我曾经遇到过类似的问题,我使用了一个哈希列。该值太大,无法索引(>1K),我还需要将该值转换为一个ID来存储(基本上是一个字典)。大致如下:

create table values_dictionary (
  id int not null identity(1,1),
  value varchar(8000) not null,
  value_hash = checksum(value) persisted,
  constraint pk_values_dictionary_id
     primary key nonclustered (id));
create unique clustered index cdx_values_dictionary_checksum on (value_hash, id);
go

create procedure usp_get_or_create_value_id (
   @value varchar(8000),
   @id int output)
begin
   declare @hash = CHECKSUM(@value);
   set @id = NULL;
   select @id = id
      from table
      where value_hash = @hash
      and value = @value;
  if @id is null
  begin
      insert into values_dictionary (value)
        values (@value);
      set @id = scope_identity();
  end
end
在这种情况下,字典表被组织为
values\u hash
列上的聚集索引,该列将所有冲突的hash值分组在一起。添加了
id
列以使聚集索引唯一,从而避免了对索引的需要。这种结构使
@value
的查找尽可能高效,在
value
上没有非常低效的索引,并且绕过了900个字符的限制。
id
上的主键是非聚集的,这意味着从和
id
中查找
值会增加聚集索引中一个额外探测的开销


不确定这是否解决了你的问题,你显然比我更了解你的实际情况。此外,代码不处理错误条件,实际上可以插入重复的@value条目,这可能是正确的,也可能是错误的。

因此,基本上,在我有这个大varchar列的情况下,我必须坚持不使用索引?我还提供了一个链接示例:创建索引IX_Address_PostalCode on Person.Address(PostalCode)包括(AddressLine1、AddressLine2、City、StateProvinceID);在提供的示例中,似乎只有PostalCode对索引大小起作用。当查询AddressLine1列(例如“WHERE AddressLine1=@Addr1”)时,这是否有助于提高性能?如果没有上下文,您的问题不会特别有用。为什么你认为你需要一个索引?您将如何使用它?请参阅下面的评论Remus Rusanu。如果您必须使用长字符串进行此类操作,您是否知道使用它是否有用。感谢您指出Remus。这实际上是有道理的。我想我主要是在inserts中使用这个列来定位它是否已经存在(以及它关联的行唯一id),这样我就可以在另一个表中将该列的id作为外键引用。这是有道理的:-)?因此,主要针对所描述的情况:其中column='ABC'+1,我考虑在散列上添加索引,但想知道如何处理冲突,从未想过在散列和id列上都有索引。