【问题标题】:SQL server - worth indexing large string keys?SQL server - 值得索引大字符串键吗?
【发布时间】:2018-01-12 07:26:54
【问题描述】:

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

如果我想在这个大列上建立索引,我有哪些选择?如果可以的话,我不知道是否值得。

【问题讨论】:

  • 如果没有上下文,您的问题并不是特别有用。为什么你认为你需要一个索引?你会如何使用它?
  • 见下方评论 Remus Rusanu
  • 如果您必须使用长字符串来处理这类事情,任何人都知道使用 msdn.microsoft.com/en-us/library/ms174415.aspx 是否有用。

标签: sql-server


【解决方案1】:

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

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

  • 探测值时。这是最典型的用途,是在表中搜索精确值时。典型示例是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 上的主键是非聚集的,这意味着从 id 和 id 查找 value 会导致在聚集索引中额外进行一次探测的开销。

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

【讨论】:

  • 感谢 Remus 指出这一点。这实际上是有道理的。我想我主要在插入时使用此列来定位它是否已经存在(并且它是关联的行唯一 ID),以便我可以将该列的 ID 作为另一个表中的外键引用。那讲得通 :-) ?所以主要针对案例描述:WHERE column='ABC'
  • +1,我想过在哈希列上添加索引,但想知道如何处理冲突,从未想过在哈希列和 id 列上都有索引。
【解决方案2】:

General Index Design Guidelines

当您设计索引时,请考虑以下列准则:

  • 对聚集索引保持索引键的长度较短。此外,聚集索引受益于在唯一的 或非空列。有关详细信息,请参阅聚集索引设计 指导方针。

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

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

【讨论】:

  • 所以基本上在我有这么大的 varchar 列的情况下,我只需要坚持不使用索引吗?我还在提供的链接上提供了一个示例:CREATE INDEX IX_Address_PostalCode ON Person.Address (PostalCode) INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID);在提供的示例中,似乎只有 PostalCode 才算索引大小。在查询 AddressLine1 列(例如“WHERE AddressLine1=@Addr1”)时,这是否有助于提高性能?
猜你喜欢
  • 1970-01-01
  • 2010-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多