SQL 表變數與臨時表

2021-09-14 06:55:23 字數 4802 閱讀 6392

表變數在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這樣的語句中。

表變數不能做如下事情:

雖然表變數是乙個變數,但是其不能賦值給另乙個變數。

check約束,預設值和計算列不能引用自定義函式。

不能為約束命名。

不能truncate表變數。

不能向標識列中插入顯式值(也就是說表變數不支援set identity_insert on)

在深入臨時表之前,我們要了解一下會話(session),乙個會話僅僅是乙個客戶端到資料引擎的連線。在sql server management studio中,每乙個查詢視窗都會和資料庫引擎建立連線。乙個應用程式可以和資料庫建立乙個或多個連線,除此之外,應用程式還可能建立連線後一直不釋放知道應用程式結束,也可能使用完釋放連線需要時建立連線

臨時表和create table語句建立的表有著相同的物理工程,但臨時表與正常的表不同之處有:

臨時表的名稱不能超過116個字元,這是由於資料庫引擎為了辨別不同會話建立不同的臨時表,所以會自動在臨時表的名字後附加一串

區域性臨時表(以"#"開頭命名的)作用域僅僅在當前的連線內,從在儲存過程中建立區域性臨時表的角度來看,區域性臨時表會在下列情況下被drop:

顯示呼叫drop table語句

當區域性臨時表在儲存過程內被建立時,儲存過程結束也就意味著區域性臨時表被drop

.當前會話結束,在會話內建立的所有區域性臨時表都會被drop

全域性臨時表(以"##"開頭命名的)在所有的會話內可見,所以在建立全域性臨時表之前首先檢查其是否存在,否則如果已經存在,你將會得到重複建立物件的錯誤

全域性臨時表會在建立其的會話結束後被drop,drop後其他會話將不能對全域性臨時表進行引用。

引用是在語句級別進行,如:

新建查詢視窗,執行語句:

create table ##temp(rowid int)

insert into ##temp values(3)

再次新建乙個查詢視窗,每5秒引用一次全域性臨時表

while 1=1

begin

select * from ##temp

waitfor delay '00:00:05'

end不能對臨時表進行分割槽

不能對臨時表加外來鍵約束

臨時表內列的資料型別不能定義成沒有在tempdb中沒有定義自定義資料型別(自定義資料型別是資料庫級別的物件,而臨時表屬於tempdb)。由於tempdb在每次sql server重啟後會被自動建立,所以你必須使用startup stored procedure來為tempdb建立自定義資料型別。你也可以通過修改model資料庫來達到這一目標

xml列不能定義成xml集合的形式,除非這個集合已經在tempdb中定義

臨時表既可以通過create table語句建立,也可以通過"select into #table"語句建立。還可以針對臨時錶用"insert into #table exec stored_procedure"這樣的語句

臨時表可以擁有命名的約束和索引。但是,當兩個使用者在同一時間呼叫同一儲存過程時,將會產生」there is already an object named '' in the database」這樣的錯誤。所以最好的做法是不用為建立的物件進行命名,而使用系統分配的在tempdb中唯一的

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

SQL 表變數和臨時表

sql 表變數和臨時表 表變數 儲存在記憶體中,作用域是指令碼的執行過程中,指令碼執行完畢之後就會釋放記憶體,適合短時間內儲存資料量小的資料集。優點 使用靈活,使用完之後立即釋放,不占用物理儲存空間 缺點 只適合較小資料量的暫時儲存,不能建索引,資料量稍大時查詢效率慢,佔記憶體 使用臨時表和表變數的...

SQL臨時表和表變數

表變數 儲存在記憶體中,作用域是指令碼的執行過程中,指令碼執行完畢之後就會釋放記憶體,適合短時間內儲存資料量小的資料集。優點 使用靈活,使用完之後立即釋放,不占用物理儲存空間 缺點 只適合較小資料量的暫時儲存,不能建索引 資料量稍大時查詢效率慢,佔記憶體 使用臨時表和表變數的資料量大小沒有具體的臨界...

臨時表與表變數

臨時表 表變數的比較 1 臨時表 臨時表包括 以 開頭的區域性臨時表,以 開頭的全域性臨時表。a 儲存 不管是區域性臨時表,還是全域性臨時表,都會放存放在tempdb資料庫中。b 作用域 區域性臨時表 對當前連線有效,只在建立它的儲存過度 批處理 動態語句中有效,類似於c語言中區域性變數的作用域。全...