2009-05-20 95 views
130

您可以在SQL Server 2000中的表变量上创建索引吗?在表变量上创建索引

DECLARE @TEMPTABLE TABLE (
     [ID] [int] NOT NULL PRIMARY KEY 
     ,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL 
) 

我可以创建一个名称索引?

+3

创建两种临时表都有成本;如果你有这么多的数据,你需要一个索引,它可能是时间来看待使用真正的表;您设置为交易安全;按spid或用户标识过滤,然后在最后清除它。真正的表格v临时表格都有起伏,但如果表现是一个问题;尝试一个真正的表。 – u07ch 2009-05-20 05:49:38

+0

临时表'IS'是一个真正的表格,当你完成时它就会消失。真正的区别(除了它会自动消失)是它在TempDB中。实际上,这对于索引和约束来说是非常巨大的,因为最终可能会发生名称冲突,不仅会导致其他代码执行,而且还会导致代码在您的实例中的其他数据库中执行。 – bielawski 2016-05-12 20:19:19

+0

@bielawski这是一个表变量不是临时表。表变量不允许明确指定约束,系统生成的名称保证是唯一的。他们确实允许从2014年开始使用命名索引,但这并不是问题,因为索引只需要在不跨对象的对象内唯一命名。 – 2017-11-04 17:59:54

回答

256

这个问题被标记为SQL Server 2000,但为了开发最新版本的人的利益,我会先解决这个问题。

的SQL Server 2014

除了添加的SQL Server 2014下面所讨论的基于约束指数的方法也允许对表的变量声明直列语法直接指定的非唯一索引。

举例说明语法如下。

/*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声明表格变量的过滤索引。通过RTM它可能是包括列也允许的,但目前的立场是,他们"will likely not make it into SQL16 due to resource constraints"

/*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

我可以创造一个名称索引?

简答:是的。

DECLARE @TEMPTABLE TABLE (
    [ID] [INT] NOT NULL PRIMARY KEY, 
    [Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL, 
    UNIQUE NONCLUSTERED ([Name], [ID]) 
) 

更详细的答案如下。

SQL Server中的传统表可以具有聚簇索引或结构为heaps

聚集索引可以声明为唯一的,以禁止重复键值或默认为非唯一。如果不是唯一的,那么SQL Server会默认将uniqueifier添加到任何重复键以使其唯一。

非聚集索引也可以显式声明为唯一。否则,对于非唯一的情况SQL Server adds the row locator(堆聚簇索引键或RID堆)到所有索引键(不只是重复),这再次确保它们是唯一的。

在SQL Server 2000 - 2012中,只能通过创建UNIQUEPRIMARY KEY约束来隐式创建表变量的索引。这些约束类型之间的区别在于主键必须位于不可空列上。参与唯一约束的列可以是空的。 (尽管SQL Server在存在NULL时存在唯一约束的实现不符合SQL标准中指定的限制)。另外一个表只能有一个主键但有多个唯一约束。

这两个逻辑约束都是通过一个唯一的索引在物理上实现的。如果没有明确说明,否则所述PRIMARY KEY将成为聚簇索引和唯一约束的非聚集但这种行为可以通过与约束声明,指明CLUSTEREDNONCLUSTERED明确地(实施例语法)

DECLARE @T TABLE 
(
A INT NULL UNIQUE CLUSTERED, 
B INT NOT NULL PRIMARY KEY NONCLUSTERED 
) 

作为上述的结果被重写可以在SQL Server 2000 - 2012的表变量上隐式创建以下索引。

+-------------------------------------+-------------------------------------+ 
|    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非唯一非聚集索引是通过对Name,Id一个唯一指数模拟的(记得,SQL服务器将默默地聚集索引键添加到非唯一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中实现,因为这增加了“Uniqueifier”的所有行的精确仿真。不只是那些需要它的人。

11

应该理解,从性能的角度来看,@ temp表和喜欢变量的#temp表没有区别。它们驻留在同一个地方(tempdb),并以相同的方式实现。所有差异都显示在附加功能中。看到这个惊人的完整的写作:https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

虽然有些情况下不能使用临时表,如表或标量函数,对于大多数其他情况下,在v2016之前(即使过滤索引可以添加到表变量),你可以简单地使用#temp表。

在tempdb中使用命名索引(或约束)的缺点是名称可能会发生冲突。不仅在理论上与其他程序,而且往往很容易与程序本身的其他实例,它会试图将相同的索引放在#temp表的副本上。

为了避免名称冲突,这样的事情通常工作:

declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);'; 
exec (@cmd); 

这将确保该名称是始终即使同样的顺序,同时执行之间唯一的。