我有一个表,有一个大的字符串键(varchar(1024)),我想在SQL服务器上索引(我希望能够快速搜索它,但也插入是重要的)。在sql 2008中,我没有得到这个警告,但在sql server 2005下它告诉我它超过了900个字节,并且插入/更新这个大小的列将被丢弃(或者在那个区域中的某个东西)SQL服务器 - 值得索引的大字符串键?
如果我想在这个大型专栏中编制索引,我有什么选择?无论如何,我不知道这是否值得。
我有一个表,有一个大的字符串键(varchar(1024)),我想在SQL服务器上索引(我希望能够快速搜索它,但也插入是重要的)。在sql 2008中,我没有得到这个警告,但在sql server 2005下它告诉我它超过了900个字节,并且插入/更新这个大小的列将被丢弃(或者在那个区域中的某个东西)SQL服务器 - 值得索引的大字符串键?
如果我想在这个大型专栏中编制索引,我有什么选择?无论如何,我不知道这是否值得。
的指数近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
上的主键是非群集的,这意味着查找value
和id
会在聚簇索引中产生一个额外探针的开销。
不知道这是否回答你的问题,你显然比我更了解你的实际情况。此外,该代码不处理错误条件,并且实际上可以插入重复的@value条目,这些条目可能正确也可能不正确。
感谢您指出了Remus。这实际上是有道理的。我想我主要是在inserts中使用这个列来定位它是否已经存在(并且它是关联的行唯一id),以便我可以在另一个表中引用该列的id作为外键。这就说得通了 :-) ?所以主要针对所描述的情况:WHERE column ='ABC' – Ghita
+1,我想过在哈希列上添加索引,但想知道如何处理碰撞,从来没有想过在哈希列和id列上都有索引。 –
General Index Design Guidelines
当你设计一个索引考虑以下列准则:
保持索引键短聚簇索引的长度。此外,聚簇索引可以在独特的 或非空列上创建。有关更多信息,请参阅聚集索引设计 准则。
无法将ntext,text,image,varchar(max),nvarchar(max)和varbinary(max)数据类型的列指定为 索引键列。但是,varchar(max),nvarchar(max), varbinary(max)和xml数据类型可作为非键索引列参与非聚集索引 索引。有关更多信息,请参阅索引 包含的列。
检查列中的数据分布。通常,长时间运行的查询是由索引少数唯一值的列引起的,或者由在这样的列上执行连接引起的。这是 数据和查询的基本问题,如果没有 识别这种情况,通常无法解决。例如,物理电话 目录按字母顺序排序的姓氏,也无法加快 定位个人,如果在城市所有的人被命名为史密斯和琼斯
因此,基本上在我的情况下,我有这个大的varchar列,我只需要坚持不使用索引呢?我也是这样一个链接的例子: CREATE INDEX IX_Address_PostalCode ON Person.Address(PostalCode) INCLUDE INCLUDE(AddressLine1,AddressLine2,City,StateProvinceID);在提供的示例中,似乎只有PostalCode计算索引大小。当查询AddressLine1列(例如“WHERE AddressLine1 = @ Addr1”)时,这是否有助于提高性能? – Ghita
没有上下文,你的问题不是特别有用。你为什么认为你需要一个索引?你会如何使用它? – Anon246
请参阅下面的注释Remus Rusanu – Ghita
任何人都知道如果使用https://msdn.microsoft.com/en-us/library/ms174415.aspx是否有用,如果您必须使用长字符串来处理此类事情。 – HumbleWebDev