轉:表變量與臨時表的優缺點

什麼情況下使用表變量? 
什麼情況下使用臨時表?

------------------------------------------------------------------------------------------------------------------------------

表變量在批處理結束時自動被系統刪除,所以你不必要像使用臨時表一樣顯示的對它進行刪除.
表變量和臨時錶針對我們使用人員來說並沒有什麼不同,但是在存儲方面來說,他們是不同的,表變量存儲在內存中.所以在性能上和臨時表相比會更好些! 
3個理論上的不同。
第一個不同是事務日誌不會記錄表變量。因此它們脫離了事務機制的範圍。
第二個主要的不同是任何一個使用臨時表的存儲過程都不會被預編譯,然而使用表變量的存儲過程的執行計劃可以預先靜態的編譯。預編譯一個腳本的主要好處在於加快了執行的速度。這個好處對於長的存儲過程更加顯著因爲對它來說重新編譯代價太高.
最後表變量僅存在於那些變量能存在的相同範圍內。和臨時表相反它們在內部存儲過程和execstring語句裏是不可見的。它們也不能在insert/exec語句裏使用


------------------------------------------------------------------------------------------------------------------------------

表變量只存放在內存中,臨時表需要寫磁盤。所以一般情況下,用表變量會快些。

用法不太一樣,有些時候用表變量更方便。

 

1.表變量在內存中,臨時表存放在硬盤上; 
2.用臨時表要考慮鎖不鎖表的問題; 
3.數據量太大應該用臨時表。

 

1、表變量缺省放在內存,速度快,所以在觸發器,存儲過程裏如果數據量不大,應該用表變量。 
2、 臨時表缺省使用硬 盤,一般來說速度比較慢,那是不是就不用臨時表呢?也不是,在數據量比較大的時候,如果使用表變量,會把內存耗盡,然後使用TEMPDB的空間,這樣主要 還是使用硬盤空間,但同時把內存基本耗盡,增加了內存調入調出的機會,反而降低速度。這種情況建議先給TEMPDB一次分配合適的空間,然後使用臨時表。

------------------------------------------------------------------------------------------------------------------------------

膚淺理解: 
表變量:需要事先知道表結構 
普通臨時表:只在當前會話中可用與表變量相同 into一下就可以了,方便 
全局臨時表:可在多個會話中使用存在於temp中需顯示的drop


------------------------------------------------------------------------------------------------------------------------------

要從表變量的作用域,支持不支持的操作,機器內存大小等幾方面考慮。 
如: 
.表變量相當於ADO的RECORDSET,速度比臨時錶快得多。 
表變量不能用在下列語句中: 
INSERT INTO table_variable EXEC 存儲過程。 
SELECT select_list INTO table_variable 語句。


在定義 table 變量的函數、存儲過程或批處理結束時,自動清除 table 變量。 
但臨時表支持。


.表變量速度比臨時錶快得多(如果內存足夠) 
如果數據量不大: 
微軟 BOOK ON LINE 內說:儘可能使用表變量而不使用臨時表 
------------------------------------------------------------------------------------------------------------------------------

 

表變量有以下優點:

table 變量的行爲類似於局部變量,有明確定義的作用域。該作用域爲聲明該變量的函數、存儲過程或批處理。 
在其作用域內,table 變量可像常規表那樣使用。該變量可應用於 SELECT、INSERT、UPDATE 和 DELETE 語句中用到表或表的表達式的地方。

但是,table 不能用在下列語句中:

INSERT INTO table_variable EXEC 存儲過程。

SELECT select_list INTO table_variable 語句。

在定義 table 變量的函數、存儲過程或批處理結束時,自動清除 table 變量。

在存儲過程中使用表變量與使用臨時表相比,減少了存儲過程的重新編譯量。


涉及表變量的事務只在表變量更新期間存在。這樣就減少了表變量對鎖定和記錄資源的需求。 
不支持在表變量之間進行賦值操作。另外,由於表變量作用域有限,並且不是持久數據庫的一部分,因而不受事務回滾的影響。

 

表變量和臨時表對比總結

特性

表變量

臨時表

作用域

當前批處理

當前會話,嵌套存儲過程,全局:所有會話

使用場景

自定義函數,存儲過程,批處理

自定義函數,存儲過程,批處理

創建方式

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之前定義臨時表

 

二、

表變量存儲在內存中,而臨時表存儲在tempdb中,會涉及到物理IO讀寫,那麼我們是否可以由此得出結論,使用表變量要比使用臨時表效率高呢?相信有一部分人會和我有同樣的想法,使用表變量的效率高,真是如此嗎?先從一次優化存儲過程的經歷說起。

      存儲過程涉及到兩個表,一個是用戶今日積分表@tableUserScore(數據源來自用戶積分詳情表中的今日數據),一個是用戶積分統計表 UserScoreSum,該存儲過程邏輯就是統計@tableUserScore中用戶不同原因的積分值,生成到表UserScoreSum中。數據量 不算很大,@tableUserScore中大概40萬條,但這個存儲過程執行時間卻有些驚人,通常都在1個小時之上。優化的最終結果是將表變量@tabeUserScore換成了臨時表#tableUserScore,並在userid和reason上添加了聯合索引,優化的效果是執行時間控制在了40S左右。臨時表和表變量效率相差百倍,這次優化經歷讓我對臨時表和表變量有了重新認識,也有了一連串的疑問,它們是如何存儲的,效率如何,如何選用?

複製代碼

declare@tableUserScoretable(  
userid int, --用戶編號  
name varchar(10), --用戶姓名  
reason varchar(32), --積分原因  
score int--積分值  
)  
  
createtable UserScoreSum(  
userid int, --用戶編號  
name varchar(10), --用戶姓名  
createTime datetime, --時間  
reason1Score int, --原因1積分值  
reason2Score int, --原因2積分值  
reason3Score int, --原因3積分值  
reason4Score int, --原因4積分值  
)  

複製代碼

 

     以下是個人翻閱資料後的理解,總結出來希望能給和我有同樣認識的人提個醒,起到拋磚引玉的作用,也希望大家對理解錯誤之處提出指正。

     臨時表

     臨時表有兩種類型:本地表和全局表。在與首次創建或引用表時相同的 SQL Server 實例連接期間,本地臨時表只對於創建者是可見的。當用戶與 SQL Server 實例斷開連接後,將刪除本地臨時表。全局臨時表在創建後對任何用戶和任何連接都是可見的,當引用該表的所有用戶都與 SQL Server 實例斷開連接後,將刪除全局臨時表。本地臨時表的名稱都是以“#”爲前綴,全局臨時表的名稱都是以“##”爲前綴。

     臨時表存儲在tempdb中,因此臨時表的訪問是有可能造成物理IO的,當然在修改時也需要生成日誌來確保一致性,同時鎖機制也是不可缺少的。

     臨時表可以創建索引,也可以定義統計數據,所以可以用數據定義語言(DDL)的聲明來阻止臨時表添加的限制,約束,並參照完整性,如主鍵和外鍵約束。

     表變量

     表變量是變量的一種,表變量也分爲本地及全局的兩種,本地表變量的名稱都是以“@”爲前綴,只有在本地當前的用戶連接中才可以訪問。全局的表變量的名稱都 是以“@@”爲前綴,一般都是系統的全局變量,像我們常用到的,如@@Error代表錯誤的號,@@RowCount代表影響的行數。

     表變量存放在內存中,正是因爲這一點所有用戶訪問表變量的時候SQL Server是不需要生成日誌。同時變量是不需要考慮其他會話訪問的問題,因此也不需要鎖機制,對於非常繁忙的系統來說,避免鎖的使用可以減少一部分系統負載。[表變量存放在內存是有一定限制的,如果表變量數據量超過閾值,會把內存耗盡,然後使用TempDB的空間,這樣主要還是使用硬盤空間,但同時把內存基本耗盡,增加了內存調入調出的機會,反而降低速度]

     表變量另外還有一個限制就是不能創建索引,當然也不存在統計數據的問題,因此在用戶訪問表變量的時候也就不存在執行計劃選擇的問題了(也就是以爲着編譯階段後就沒有優化階段了),這一特性有的時候是件好事,而有些時候卻會造成一些麻煩。

     臨時表 vs. 表變量

     1.存儲位置:臨時表是利用了硬盤(tempdb數據庫) ,表名變量是佔用內存,因此小數據量當然是內存中的表變量更快。當大數據量時,就不能用表變量了,太耗內存了。大數據量時適合用臨時表。

     2.性能:不能一概而論,表變量存儲數據有個性能臨界點,在這個臨界點之內,表變量比臨時錶快,表變量是存儲在內存中的。

     3.索引:表變量不支持索引和統計數據,但可以有主鍵;臨時表則可以支持索引和統計數據。

     我們對於較小的臨時計算用數據集考慮使用表變量。如果數據集比較大,如果 在代碼中用於臨時計算,同時這種臨時使用永遠都是簡單的全數據集掃描而不需要考慮什麼優化,比如說沒有分組或分組很少的聚合(比如說COUNT、SUM、 AVERAGE、MAX等),也可以考慮使用表變量。使用表變量另外一個考慮因素是應用環境的內存壓力,如果代碼的運行實例很多,就要特別注意內存變量對 內存的消耗。一般對於大的數據集我們最好使用臨時表,同時創建索引。

 

PS:抱歉,沒有找到原作者,引用cnblog的地址也是轉載,這裏就不說明了,如果坐着看到,可以聯繫我添加引用地址。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章