在表variables上创build一个索引
你可以在SQL Server 2000的表variables上创build一个索引吗?
即
DECLARE @TEMPTABLE TABLE ( [ID] [int] NOT NULL PRIMARY KEY ,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL )
我可以在名称上创build一个索引吗?
这个问题被标记为SQL Server 2000,但是为了开发最新版本的人员的利益,我将首先解决这个问题。
SQL Server 2014
除了下面讨论的添加基于约束的索引的方法之外,SQL Server 2014还允许使用表variables声明的内联语法直接指定非唯一索引。
这个例子的语法如下。
/*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为表variables声明过滤索引。 通过RTM, 可能会出现这样的情况:包含的列也是允许的,但是现在的位置是“由于资源限制 ,它们可能不会成为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
我可以在名称上创build一个索引吗?
简短的回答:是的。
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年,只能通过创build一个UNIQUE
或PRIMARY KEY
约束来隐式创build表variables的索引。 这些约束types的区别在于主键必须位于不可空列上。 参与唯一约束的列可以是空的。 (尽pipe在存在NULL
的情况下,SQL Server对唯一约束的实现不是按照SQL标准中指定的)。 另外一个表只能有一个主键但是有多个唯一的约束。
这两个逻辑约束都是通过一个唯一的索引在物理上实现的。 如果未明确指定, PRIMARY KEY
将成为非聚簇的聚簇索引和唯一约束,但是可以通过使用约束声明(示例语法)明确指定CLUSTERED
或NONCLUSTERED
来覆盖此行为。
DECLARE @T TABLE ( A INT NULL UNIQUE CLUSTERED, B INT NOT NULL PRIMARY KEY NONCLUSTERED )
由于以上原因,SQL Server 2000 – 2012中的表variables可隐式创build以下索引。
+-------------------------------------+-------------------------------------+ | 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 | +-------------------------------------+-------------------------------------+
最后一个需要一点解释。 在这个答案开头的表variables定义中, Name
上的非唯一非聚集索引是通过Name,Id
上的唯一索引来模拟的(回想起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) )
但是,这不是一个准确的模拟,如何在SQL Server中实际实现非唯一聚集索引,因为这会将“独一无二”添加到所有行。 不只是那些需要它。
应该明白,从性能的angular度来看,@ temp表和喜欢variables的#temp表没有区别。 它们驻留在同一个地方(tempdb),并以相同的方式实现。 所有差异都显示在附加function中。 看到这个惊人的完整的写作: https ://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386
尽pipe在某些情况下临时表不能用于表格或标量函数,但对于v2016之前的大多数其他情况(甚至可以将过滤后的索引添加到表variables中),只需使用#temp表即可。
在tempdb中使用命名索引(或约束)的缺点是名称可能会冲突。 不仅在理论上与其他程序,而且往往很容易与程序本身的其他实例,试图将相同的索引放在#temp表的副本。
为了避免名称冲突,通常这样的工作:
declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);'; exec (@cmd);
这确保了即使在同时执行同一过程之间,名称也是唯一的。