2011-11-03 61 views
8

我有一个表,有一个大的字符串键(varchar(1024)),我想在SQL服务器上索引(我希望能够快速搜索它,但也插入是重要的)。在sql 2008中,我没有得到这个警告,但在sql server 2005下它告诉我它超过了900个字节,并且插入/更新这个大小的列将被丢弃(或者在那个区域中的某个东西)SQL服务器 - 值得索引的大字符串键?

如果我想在这个大型专栏中编制索引,我有什么选择?无论如何,我不知道这是否值得。

+1

没有上下文,你的问题不是特别有用。你为什么认为你需要一个索引?你会如何使用它? – Anon246

+0

请参阅下面的注释Remus Rusanu – Ghita

+0

任何人都知道如果使用https://msdn.microsoft.com/en-us/library/ms174415.aspx是否有用,如果您必须使用长字符串来处理此类事情。 – HumbleWebDev

回答

13

的指数近900个字节的所有按键会非常大且非常深(每页只有很少的键会导致非常高的B-Trees)。

这取决于你打算如何计划查询的值。在几种情况下索引是有用的:

  • 当一个值被探测。这是最典型的用法,就是在表格中搜索确切的值时。典型示例是WHERE column='ABC'或加入条件ON a.column = B.someothercolumn
  • 扫描范围时。当在表格中搜索值时,这也是相当典型的范围。除了WHERE column BETWEEN 'ABC' AND 'DEF'的明显例子,还有其他不太明显的例子,比如部分匹配:WHERE column LIKE 'ABC%'
  • 订购要求。这种用法不太为人所知,但索引可以帮助具有明确ORDER BY column要求的查询,以避免停顿和排序,还可以帮助某些隐藏的排序要求,如ROW_NUMBER() OVER (ORDER BY column)

那么,你为什么需要索引?什么样的查询会使用它?

对于范围扫描和订购要求,没有其他解决方案,但有索引,你将不得不权衡指数成本与收益。

对于探测器,您可以使用散列来避免索引非常大的列。创建一个持久计算列作为column_checksum = CHECKSUM(column),然后索引该列。查询必须重写为使用WHERE column_checksum = CHECKSUM('ABC') AND column='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_hash柱其中所有的碰撞散列值基团一起聚簇索引。添加id列以使聚簇索引唯一,从而避免需要hidden uniqueifier column。该结构使@value的查找尽可能高效,而不是value上的效率非常低的索引,并绕过了900个字符的限制。 id上的主键是非群集的,这意味着查找valueid会在聚簇索引中产生一个额外探针的开销。

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

+0

感谢您指出了Remus。这实际上是有道理的。我想我主要是在inserts中使用这个列来定位它是否已经存在(并且它是关联的行唯一id),以便我可以在另一个表中引用该列的id作为外键。这就说得通了 :-) ?所以主要针对所描述的情况:WHERE column ='ABC' – Ghita

+0

+1,我想过在哈希列上添加索引,但想知道如何处理碰撞,从来没有想过在哈希列和id列上都有索引。 –

1

General Index Design Guidelines

当你设计一个索引考虑以下列准则:

  • 保持索引键短聚簇索引的长度。此外,聚簇索引可以在独特的 或非空列上创建。有关更多信息,请参阅聚集索引设计 准则。

  • 无法将ntext,text,image,varchar(max),nvarchar(max)和varbinary(max)数据类型的列指定为 索引键列。但是,varchar(max),nvarchar(max), varbinary(max)和xml数据类型可作为非键索引列参与非聚集索引 索引。有关更多信息,请参阅索引 包含的列。

  • 检查列中的数据分布。通常,长时间运行的查询是由索引少数唯一值的列引起的,或者由在这样的列上执行连接引起的。这是 数据和查询的基本问题,如果没有 识别这种情况,通常无法解决。例如,物理电话 目录按字母顺序排序的姓氏,也无法加快 定位个人,如果在城市所有的人被命名为史密斯和琼斯

+0

因此,基本上在我的情况下,我有这个大的varchar列,我只需要坚持不使用索引呢?我也是这样一个链接的例子: CREATE INDEX IX_Address_PostalCode ON Person.Address(PostalCode) INCLUDE INCLUDE(AddressLine1,AddressLine2,City,StateProvinceID);在提供的示例中,似乎只有PostalCode计算索引大小。当查询AddressLine1列(例如“WHERE AddressLine1 = @ Addr1”)时,这是否有助于提高性能? – Ghita