大型nvarchar列的SQL Server索引失败

时间:2017-05-10 12:31:56

标签: sql-server indexing

我有一个大小为2000的nvarchar列。有时当我插入时,它会因错误而失败:

  

System.Data.SqlClient.SqlException:操作失败。索引条目   索引的长度为1146字节' NonClusteredIndex-20161206-202443'   超过最大长度900字节。

但我不知道该怎么做。该表有45m记录,因此必须有索引。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

索引这么大的字符串列通常是一个相当糟糕的标志。我首先会问你是否真的想要一个全文索引。这对文本而言比对常规索引更有用。

如果确实需要索引,则可以使用计算列提取一定数量的字符并在其上构建索引:

(?>o(?>o(?>o(?>o(?>oo)?o)?o)?o)?o)    
o   |oooooo                         <- first o gets matched by first atomic group
o   o   |ooooo                      <- second o accordingly
o   o   o   |oooo                   <- third o accordingly
o   o   o   o   |ooo                <- fourth o accordingly
o   o   o   o   oo|o                <- fifth/sixth o by the innermost atomic group
o   o   o   o   oo  o|              <- fourth ag is matched successfully (thus no backtracking into it)
                         ^          <- no more o, so backtracking starts here, no backtracking into fourth ag, try again 3rd
o   o   o                |ooo<o     <- 3rd ag can be closed, as well as second and first -> match returned (6 os)

请确保对应使用索引的任何表达式使用alter table t add col100 as (left(col, 100)); create index ind_t_col100 on t(col100);

如果索引的目的是保证唯一性,那么您可以计算校验和和前100个字符,并为这些值创建唯一索引。

答案 1 :(得分:0)

另一个解决方案是使用CHECKSUMref)函数创建计算列,然后创建一个索引(ref),将此计算列作为索引键,并将原始列包含在内专栏:

SET NUMERIC_ROUNDABORT OFF
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON
GO

ALTER TABLE dbo.SomeTable
ADD TextChekcsum AS (CHECKSUM([TextColumn])) -- Non persisted computed column
--or ADD TextChekcsum AS (HASHBYTES'sha1', CHECKSUM([TextColumn]))) 
GO

CREATE INDEX IX_SomeTable_TextChekcsum_#_TextColumn
ON dbo.SomeTable (TextChecksum)
INCLUDE(TextColumn)
GO

-- In this case, in order to query this column I would use following approach:
DECLARE @ValueToSearch NVARCHAR(4000) -- Replace NVARCHAR(4000) with proper data type and max. length

SELECT ID, TextColumn
FROM dbo.SomeTable st
WHERE st.TextCheksum = CHECKSUM(@ValueToSearch)
--WHERE st.TextCheksum = HASHBYTES('sha1', CHECKSUM(@ValueToSearch))
AND st.TextColumn = @ValueToSearch
GO

注意:根据MS文档(ref

  

创建索引的连接以及所有连接   尝试INSERT,UPDATE或DELETE语句来改变其中的值   索引必须将六个SET选项设置为ON并将一个选项设置为   关闭。优化程序忽略任何计算列上的索引   SELECT语句由没有这些的连接执行   相同的选项设置。

第二个注释:SELECT CHECKSUM(HASHBYTES('sha1', N''))返回917799192 ans SELECT CHECKSUM(HASHBYTES('sha1', N''))返回468415091