在 varchar(1024) 列上创建索引成功。它有效吗?

yob*_*ioo 6 sql-server sql-server-2012

当我使用 SSMS GUI 在 varchar(1024) 列上创建索引时,它失败并显示以下消息:

"Warning! The maximum key length is 900 bytes. The index 'XXX' has maximum length of 1024 bytes. For some combination of large values, the insert/update operation will fail." 
Run Code Online (Sandbox Code Playgroud)

但是,当我使用 SQL(不是 GUI)时,同样的操作成功了。我不确定为什么会发生这种情况,但这是否意味着索引会一直工作,直到超过 900 字节的数据真正插入到列中?

(该列当前没有超过 900 字节的值。)

环境: - SQL Sever 2012 - Windows Server 2008 R2 SP1

Joh*_* N. 14

所有版本

如果在定义长度超过 900 或 1700(取决于索引的版本和类型)的列上创建索引,您将收到警告并且索引创建将成功(如果表为空或现有数据不是那么长)或错误并且索引创建将失败(如果一行或更多行超过限制)。

对于警告情况,限制为:

SQL Server 2014 及更早版本

如果您在varchar(>900)列上创建聚集索引,您将在创建索引时收到警告。

如果您在varchar(>900)列上创建非聚集索引,您将在创建索引时收到警告消息。

SQL Server 2016 及更高版本

如果您在varchar(>900)列上创建聚集索引,您将在创建索引时收到一条警告消息。

如果您在varchar(>1700)列上创建非聚集索引,您将在创建索引时收到警告消息。

插入数据

如果您插入的数据不超过索引和 SQL Server 版本的限制,那么您将不会在您的应用程序/SSMS/SQL 查询/...

但是,插入超过版本和索引类型指定的限制将导致错误消息。

测试

您可以在db<>fiddle 上尝试一下。测试示例下方提供了每个测试的链接。

SQL Server 2012 上的 Varchar 非聚集索引限制

CREATE TABLE VarcharNonClustered
(
  ID INT
  ,Name VARCHAR(2000)
)

GO
Run Code Online (Sandbox Code Playgroud)
?
CREATE NONCLUSTERED INDEX idx_VarcharNonClustered_Name ON VarcharNonClustered(Name)
GO
Run Code Online (Sandbox Code Playgroud)
?

警告!最大密钥长度为 900 字节。索引“idx_VarcharNonClustered_Name”的最大长度为 2000 字节。对于某些大值组合,插入/更新操作将失败。
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',1701))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引 'idx_VarcharNonClustered_Name' 的长度为 1701 字节的索引条目超过了最大长度 900 字节。
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',1700))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引“idx_VarcharNonClustered_Name”的长度为 1700 字节的索引条目超过了最大长度 900 字节。
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',901))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引 'idx_VarcharNonClustered_Name' 的长度为 901 字节的索引条目超过了 900 字节的最大长度。
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',900))
GO
Run Code Online (Sandbox Code Playgroud)
1 行受影响

db<>在这里摆弄

SQL Server 2012 上的 Varchar 聚集索引限制

CREATE TABLE VarcharClustered
(
  ID INT
  ,Name VARCHAR(2000)
)
GO
Run Code Online (Sandbox Code Playgroud)
?
CREATE CLUSTERED INDEX idx_VarcharClustered_Name ON VarcharClustered(Name)
GO
Run Code Online (Sandbox Code Playgroud)
?

警告!最大密钥长度为 900 字节。索引“idx_VarcharClustered_Name”的最大长度为 2000 字节。对于某些大值组合,插入/更新操作将失败。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',1701))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引 'idx_VarcharClustered_Name' 的长度为 1701 字节的索引条目超过了最大长度 900 字节。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',1700))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引“idx_VarcharClustered_Name”的长度为 1700 字节的索引条目超过了最大长度 900 字节。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',901))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引 'idx_VarcharClustered_Name' 的长度为 901 字节的索引条目超过了 900 字节的最大长度。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',900))
GO
Run Code Online (Sandbox Code Playgroud)
1 行受影响

db<>在这里摆弄

SQL Server 2016 上的 Varchar 非聚集索引限制

CREATE TABLE VarcharNonClustered
(
  ID INT
  ,Name VARCHAR(2000)
)

GO
Run Code Online (Sandbox Code Playgroud)
?
CREATE NONCLUSTERED INDEX idx_VarcharNonClustered_Name ON VarcharNonClustered(Name)
GO
Run Code Online (Sandbox Code Playgroud)
?

警告!非聚集索引的最大键长度为 1700 字节。索引“idx_VarcharNonClustered_Name”的最大长度为 2000 字节。对于某些大值组合,插入/更新操作将失败。
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',1701))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引“idx_VarcharNonClustered_Name”的长度为 1701 字节的索引条目超过了非聚集索引的最大长度 1700 字节。
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',1700))
GO
Run Code Online (Sandbox Code Playgroud)
1 行受影响
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',901))
GO
Run Code Online (Sandbox Code Playgroud)
1 行受影响
INSERT INTO VarcharNonClustered 
VALUES (1,REPLICATE('a',900))
GO
Run Code Online (Sandbox Code Playgroud)
1 行受影响

db<>在这里摆弄

SQL Server 2016 上的 Varchar 聚集索引限制

CREATE TABLE VarcharClustered
(
  ID INT
  ,Name VARCHAR(2000)
)
GO
Run Code Online (Sandbox Code Playgroud)
?
CREATE CLUSTERED INDEX idx_VarcharClustered_Name ON VarcharClustered(Name)
GO
Run Code Online (Sandbox Code Playgroud)
?

警告!聚集索引的最大键长度为 900 字节。索引“idx_VarcharClustered_Name”的最大长度为 2000 字节。对于某些大值组合,插入/更新操作将失败。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',1701))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引“idx_VarcharClustered_Name”的长度为 1701 字节的索引条目超过了聚集索引的最大长度 900 字节。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',1700))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引“idx_VarcharClustered_Name”的长度为 1700 字节的索引条目超过了聚集索引的最大长度 900 字节。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',901))
GO
Run Code Online (Sandbox Code Playgroud)
Msg 1946 Level 16 State 3 Line 1
手术失败。索引“idx_VarcharClustered_Name”的长度为 901 字节的索引条目超过了聚集索引的最大长度 900 字节。
INSERT INTO VarcharClustered 
VALUES (1,REPLICATE('a',900))
GO
Run Code Online (Sandbox Code Playgroud)
1 行受影响

db<>在这里摆弄

概括

  • SQL Server 2012 + Varchar() 上的非聚集索引 = 最多 900 个字符
  • SQL Server 2012 + Varchar() 上的聚集索引 = 最多 900 个字符
  • SQL Server 2016 + Varchar() 上的非聚集索引 = 最多 1700 个字符
  • SQL Server 2016 + Varchar() 上的聚集索引 = 最多 900 个字符

你的问题

在 varchar(1024) 列上创建索引成功。它有效吗?

它将在上述限制下工作

参考