在表变量上创建索引

Gor*_*yII 178 sql t-sql sql-server indexing table-variable

你能index在一个表变量上创建SQL Server 2000吗?

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

我可以在Name上创建索引吗?

Mar*_*ith 341

问题是标记为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*/
);
Run Code Online (Sandbox Code Playgroud)

当前无法使用此语法声明包含列的筛选索引和索引,但SQL Server 2016进一步放宽了这一点.从CTP 3.1开始,现在可以为表变量声明过滤索引.通过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*/
)
Run Code Online (Sandbox Code Playgroud)

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]) 
  ) 
Run Code Online (Sandbox Code Playgroud)

更详细的答案如下.

SQL Server中的传统表可以具有聚簇索引,也可以构造为.

可以将聚簇索引声明为唯一,以禁止重复键值,或者默认为非唯一.如果不是唯一的,则SQL Server会静默地向任何重复键添加唯一以使其唯一.

非聚簇索引也可以显式声明为唯一.否则,对于非唯一情况,SQL Server 会将行定位器(聚簇索引键或堆的RID)添加到所有索引键(而不仅仅是重复项),这再次确保它们是唯一的.

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

这两个逻辑约束都是使用唯一索引物理实现的.如果没有明确指定,PRIMARY KEY则将成为聚簇索引和非聚簇的唯一约束,但可以通过指定CLUSTEREDNONCLUSTERED显式使用约束声明来覆盖此行为(示例语法)

DECLARE @T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)
Run Code Online (Sandbox Code Playgroud)

由于上述原因,可以在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                                 |
+-------------------------------------+-------------------------------------+
Run Code Online (Sandbox Code Playgroud)

最后一个需要一些解释.在此答案开头的表变量定义中,非唯一的非聚集索引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)
)
Run Code Online (Sandbox Code Playgroud)

但这并不能准确模拟非唯一聚簇索引通常如何在SQL Server中实现,因为这会为所有行添加"Uniqueifier".不只是那些需要它的人.


bie*_*ski 13

应该理解,从性能的角度来看,@ 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);
Run Code Online (Sandbox Code Playgroud)

这确保了即使在同一程序的同时执行之间,名称也始终是唯一的.

  • 当您在存储过程中处理表变量与临时表时,实际上存在显着的性能差异。临时表受到与物理表类似的重新编译阈值的影响,而表变量提供了一种不受重新编译阈值影响的机制。在较大的程序中,这可能会导致巨大的差异。 (4认同)
  • 命名索引没有问题 - 索引只需在表中唯一命名。问题在于命名约束,最好的解决方案通常不是在临时表中命名它们 - 命名约束会阻止临时表对象缓存。 (3认同)
  • @Elaskanator 是的,他们是。我们发现在加载时 SQL 元数据表存在争用,删除索引名称解决了该问题。这是 SQL 2016。 (2认同)