2009-05-20 93 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); 

這將確保該名稱是始終即使同樣的順序,同時執行之間唯一的。