你能在SQL Server 2000上的一个表变量上创建索引吗?
即,
DECLARE @TEMPTABLE TABLE (
[ID] [int] NOT NULL PRIMARY KEY
,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL
)
我能在Name
上创建索引吗?
你能在SQL Server 2000上的一个表变量上创建索引吗?
即,
DECLARE @TEMPTABLE TABLE (
[ID] [int] NOT NULL PRIMARY KEY
,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL
)
我能在Name
上创建索引吗?
/*SQL Server 2014+ compatible inline index syntax*/
DECLARE @T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/
C2 INT INDEX IX2 NONCLUSTERED,
INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/
);
当前无法使用此语法声明筛选索引和包含列的索引,但是SQL Server 2016进一步放宽了这一限制。从CTP 3.1开始,现在可以为表变量声明筛选索引。在正式版本发布时,可能还能够允许包含列,但目前情况是他们 "由于资源限制可能不会被纳入SQL16"
/*SQL Server 2016 allows filtered indexes*/
DECLARE @T TABLE
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/
)
SQL Server 2000 - 2012
我能在Name上创建索引吗?
简短回答:是的。
DECLARE @TEMPTABLE TABLE (
[ID] [INT] NOT NULL PRIMARY KEY,
[Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL,
UNIQUE NONCLUSTERED ([Name], [ID])
)
以下是更详细的答案。
在SQL Server中,传统的表可以有聚集索引或者结构为堆。
聚集索引可以声明为唯一的,以禁止重复键值,或默认为非唯一。如果不唯一,则SQL Server会自动添加一个唯一标识符到任何重复的键上,使它们变得唯一。
非聚集索引也可以显式地声明为唯一。否则,在非唯一情况下,SQL Server会添加行定位器(聚集索引键或RID用于堆)到所有索引键(而不仅仅是重复的),这样再次确保它们是唯一的。
在 SQL Server 2000-2012 中,表变量上的索引只能通过创建 UNIQUE 或 PRIMARY KEY 约束来隐式创建。这两种约束类型的区别在于主键必须位于非空列上,而参与唯一约束的列可以为可空列。(尽管 SQL Server 在存在 NULL 时实现唯一约束的方式不符合 SQL 标准)。此外,一个表只能有一个主键,但可以有多个唯一约束。DECLARE @T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)
+-------------------------------------+-------------------------------------+
| Index Type | Can be created on a table variable? |
+-------------------------------------+-------------------------------------+
| Unique Clustered Index | Yes |
| Nonunique Clustered Index | |
| Unique NCI on a heap | Yes |
| Non Unique NCI on a heap | |
| Unique NCI on a clustered index | Yes |
| Non Unique NCI on a clustered index | Yes |
+-------------------------------------+-------------------------------------+
Name,Id
上的唯一索引模拟了Name
上的非唯一非聚集索引(请注意,SQL Server会自动将聚集索引密钥静默添加到非唯一NCI键中)。IDENTITY
列作为唯一标识符来实现非唯一聚集索引。DECLARE @T TABLE
(
A INT NULL,
B INT NULL,
C INT NULL,
Uniqueifier INT NOT NULL IDENTITY(1,1),
UNIQUE CLUSTERED (A,Uniqueifier)
)
@
开头,除非加上引号。 - Martin Smith需要理解的是,就性能而言,在@temp表和#temp表之间,并没有对变量更加有利的差异。它们存储在相同的位置(tempdb)并以相同的方式实现。所有的区别都体现在附加功能中。请参见这篇非常完整的文章:https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386
尽管存在无法使用临时表的情况,比如在表或标量函数中,但除此之外的大多数情况下,您可以简单地使用#temp表(甚至在v2016之前,其中甚至可以将过滤索引添加到表变量中)。
在tempdb中使用命名索引(或约束)的缺点是名称可能会冲突。不仅在理论上与其他过程冲突,而且经常很容易与过程本身的其他实例发生冲突,后者会尝试将相同的索引放在其#temp表的副本上。
为避免名称冲突,通常可以使用类似以下的方法:
declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (@cmd);
这确保了即使在同一程序的同时执行之间,名称始终是唯一的。
CREATE TABLE #Table(C1 int,
C2 NVarchar(100) , C3 varchar(100)
UNIQUE CLUSTERED (c1)
);
创建带有唯一聚集索引的表
将数据插入到临时表“#Table”中
创建非聚集索引。
CREATE NONCLUSTERED INDEX IX1 ON #Table (C2,C3);