表變量在SQL Server 2000中首次被引入。表變量的具體定義包括列定義,列名,數據類型和約束。而在表變量中可使用的約束包括主鍵約束,惟一約束,NULL約束和CHECK約束(外鍵約束不能在表變量中使用)。定義表變量的語句是和正常使用Create Table定義表語句的子集。只是表變量經過DECLARE @local_variable語句進行定義。數據庫
表變量的特徵:網絡
表變量擁有特定做用域(在當前批處理語句中,但不在任何當前批處理語句調用的存儲過程和函數中),表變量在批處理結束後自動被清除。 表變量較臨時表產生更少的存儲過程重編譯。 針對表變量的事務僅僅在更新數據時生效,因此鎖和日誌產生的數量會更少。 因爲表變量的做用域如此之小,並且不屬於數據庫的持久部分,因此事務回滾不會影響表變量。
表變量能夠在其做用域內像正常的表同樣使用。更確切的說,表變量能夠被當成正常的表或者表表達式同樣在SELECT,DELETE,UPDATE,INSERT語句中使用,可是表變量不能在相似"SELECT select_list INTO table_variable"這樣的語句中使用。而在SQL Server2000中,表變量也不能用於INSERT INTO table_variable EXEC stored_procedure這樣的語句中。ide
表變量不能作以下事情:函數
雖然表變量是一個變量,可是其不能賦值給另外一個變量。 check約束,默認值和計算列不能引用自定義函數。 不能爲約束命名。 不能Truncate表變量。 不能向標識列中插入顯式值(也就是說表變量不支持SET IDENTITY_INSERT ON)
在深刻臨時表以前,咱們要了解一下會話(Session),一個會話僅僅是一個客戶端到數據引擎的鏈接。在SQL Server Management Studio中,每個查詢窗口都會和數據庫引擎創建鏈接。一個應用程序能夠和數據庫創建一個或多個鏈接,除此以外,應用程序還可能創建鏈接後一直不釋放知道應用程序結束,也可能使用完釋放鏈接須要時創建鏈接性能
臨時表和Create Table語句建立的表有着相同的物理工程,但臨時表與正常的表不一樣之處有:測試
局部臨時表(以"#"開頭命名的)做用域僅僅在當前的鏈接內,從在存儲過程當中創建局部臨時表的角度來看,局部臨時表會在下列狀況下被Drop:spa
全局臨時表(以"##"開頭命名的)在全部的會話內可見,因此在建立全局臨時表以前首先檢查其是否存在,不然若是已經存在,你將會獲得重複建立對象的錯誤日誌
新建查詢窗口,運行語句:
CREATE TABLE ##temp(RowID int)
INSERT INTO ##temp VALUES(3)code
再次新建一個查詢窗口,每5秒引用一次全局臨時表
While 1=1
BEGIN
SELECT * FROM ##temp
WAITFOR delay '00:00:05'
END對象
臨時表既能夠經過Create Table語句建立,也能夠經過"SELECT <select_list> INTO #table"語句建立。還能夠針對臨時表用"INSERT INTO #table EXEC stored_procedure"這樣的語句
臨時表能夠擁有命名的約束和索引。可是,當兩個用戶在同一時間調用同一存儲過程時,將會產生」There is already an object named '<objectname>' in the database」這樣的錯誤。因此最好的作法是不用爲創建的對象進行命名,而使用系統分配的在TempDb中惟一的
這兩種觀點都是錯誤的,只有內存足夠,表變量和臨時表都會在內存中建立和處理。他們也一樣能夠在任什麼時候間被存入磁盤。注意表變量的名字是系統分配的,表變量的第一個字符」@」並非一個字母,因此它並非一個有效的變量名。系統會在TempDb中爲表變量建立一個系統分配的名稱,因此任何在sysobjects或sys.tables查找表變量的方法都會失敗
這個誤區也一樣錯誤。雖然一旦你建立一個表變量以後,就不能對其進行DDL語句了,這包括Create Index語句。然而你能夠在表變量定義的時候爲其建立索引)
declare @MyTableVariable table (RowID intPRIMARY KEY CLUSTERED)
這個語句將會建立一個擁有彙集索引的表變量。因爲主鍵有了對應的彙集索引,因此一個系統命名的索引將會被建立在RowID列上
1) SQL 並不能爲表變量創建統計信息,就像其能爲臨時表創建統計信息同樣。這意味着對於表變量,執行引擎認爲其只有1行,這也意味着針對表變量的執行計劃並非最優。雖然估計的執行計劃對於表變量和臨時表都爲1,可是實際的執行計劃對於臨時表會根據每次存儲過程的重編譯而改變。若是臨時表不存在,在生成執行計劃的時候會產生錯誤
2) 一旦創建表變量後就沒法對其進行DDL語句操做。所以若是須要爲表創建索引或者加一列,你須要臨時表
3) 表變量不能使用select …into語句,而臨時表能夠
4) 在SQL Server 2008中,你能夠將表變量做爲參數傳入存儲過程。可是臨時表不行。在SQL Server 2000和2005中表變量也不行
5) 做用域:表變量僅僅在當前的批處理中有效,而且對任何在其中嵌套的存儲過程等不可見。局部臨時表只在當前會話中有效,這也包括嵌套的存儲過程。但對父存儲過程不可見。全局臨時表能夠在任何會話中可見,可是會隨着建立其的會話終止而DROP,其它會話這時就不能再引用全局臨時表
6) 排序規則:表變量使用當前數據庫的排序規則,臨時表使用TempDb的排序規則。若是它們不兼容,你還須要在查詢或者表定義中進行指定
7) 你若是但願在動態SQL中使用表變量,你必須在動態SQL中定義表變量。而臨時表能夠提早定義,在動態SQL中進行引用
微軟推薦使用表變量,若是表中的行數很是小,則使用表變量。不少」網絡專家」會告訴你100是一個分界線,由於這是統計信息建立查詢計劃效率高低的開始。可是我仍是但願告訴你針對你的特定需求對臨時表和表變量進行測試。不少人在自定義函數中使用表變量,若是你須要在表變量中使用主鍵和惟一索引,你會發現包含數千行的表變量也依然性能卓越。但若是你須要將表變量和其它表進行join,你會發現因爲不精準的執行計劃,性能每每會很是差
爲了證實這點,請看本文的附件。附件中代碼建立了表變量和臨時表.並裝入了AdventureWorks數據庫的Sales.SalesOrderDetail表。爲了獲得足夠的測試數據,我將這個表中的數據插入了10遍。而後以ModifiedDate 列做爲條件將臨時表和表變量與原始的Sales.SalesOrderDetail表進行了Join操做,從統計信息來看IO差異顯著。從時間來看錶變量作join花了50多秒,而臨時表僅僅花了8秒
若是你須要在表創建後對錶進行DLL操做,那麼選擇臨時表
分類 | 字節輸入流 | 字節輸出流 | 字符輸入流 | 字符輸出流 |
---|---|---|---|---|
抽象基類 | InputStream | OutputStream | Reader | Writer |
特性 | 表變量 | 臨時表 | |
---|---|---|---|
做用域 | 當前批處理 | 當前會話,嵌套存儲過程,全局:全部會話 | |
使用場景 | 自定義函數,存儲過程,批處理 | 自定義函數,存儲過程,批處理 | |
建立方式 | DECLARE statement only.只能經過DECLEARE語句建立 | CREATE TABLE 語句 SELECT INTO 語句 | |
表名長度 | 最多128字節 | 最多116字節 | |
列類型 | 可使用自定義數據類型 可使用XML集合 | 自定義數據類型和XML集合必須在TempDb內定義 | |
Collation | 字符串排序規則繼承自當前數據庫 | 字符串排序規則繼承自TempDb數據庫 | |
索引 | 索引必須在表定義時創建 | 索引能夠在表建立後創建 | |
約束 | PRIMARY KEY, UNIQUE, NULL, CHECK約束可使用,但必須在表創建時聲明 | PRIMARY KEY, UNIQUE, NULL, CHECK. 約束可使用,能夠在任什麼時候後添加,但不能有外鍵約束 | |
表創建後使用DDL (索引,列) | 不容許 | 容許 | |
數據插入方式 | INSERT 語句 (SQL 2000: 不能使用INSERT/EXEC). | INSERT 語句, 包括 INSERT/EXEC. SELECT INTO 語句. | |
Insert explicit values into identity columns (SET IDENTITY_INSERT). | 不支持SET IDENTITY_INSERT語句 | 支持SET IDENTITY_INSERT語句 | |
Truncate table | 不容許 | 容許 | |
析構方式 | 批處理結束後自動析構 | 顯式調用 DROP TABLE 語句. 當前會話結束自動析構 (全局臨時表: 還包括當其它會話語句不在引用表.) | |
事務 | 只會在更新表的時候有事務,持續時間比臨時表短 | 正常的事務長度,比表變量長 | |
存儲過程重編譯 | 否 | 會致使重編譯 | |
回滾 | 不會被回滾影響 | 會被回滾影響 | |
統計數據 | 不建立統計數據,因此全部的估計行數都爲1,因此生成執行計劃會不精準 | 建立統計數據,經過實際的行數生成執行計劃 | |
做爲參數傳入存儲過程 | 僅僅在SQL Server2008, 而且必須預約義 user-defined table type. | 不容許 | |
顯式命名對象 (索引, 約束). | 不容許 | 容許,可是要注意多用戶的問題 | |
動態SQL | 必須在動態SQL中定義表變量 | 能夠在調用動態SQL以前定義臨時表 |