sqlserver 臨時表、表變量、CTE的比較

原文地址:  sqlserver 臨時表、表變量、CTE的比較html

 

一、臨時表sql

1.1 臨時表包括:以#開頭的局部臨時表,以##開頭的全局臨時表。
 
1.2 存儲
不論是局部臨時表,仍是全局臨時表,都會放存在tempdb數據庫中。
 
1.3 做用域
局部臨時表:對當前鏈接有效,只在建立它的存儲過程、批處理、動態語句中有效,相似於C#語言中局部變量的做用域。
全局臨時表:在全部鏈接對它都結束引用時,會被刪除,對建立者來講,斷開鏈接就是結束引用;對非建立者,再也不引用就是結束引用。
但最好在用完後,就經過drop  table 語句刪除,及時釋放資源。
 
1.4 特性
和普通的表同樣,能定義約束,能建立索引,最關鍵的是有數據分佈的統計信息,這樣有利於優化器作出正確的執行計劃,但同時它的開銷和普通的表同樣,通常適合數據量較大的狀況。有一個很是方便的select ... into 的用法,這也是一個特色。
 
1.5  
使用場景:
 
 
 
數據量小直接當作中間表使用,數據量較大能夠經過優化提升查詢效率,對於複雜的查詢能夠將中間結果放在臨時表中以固化執行計劃(專治執行計劃走錯)
 
 
 
 
二、表變量
 
2.1 存儲
表變量存放在tempdb數據庫中。
 
2.2 做用域
和普通的變量同樣,在定義表變量的存儲過程、批處理、動態語句、函數結束時,會自動清除。
 
2.3 特性
能夠有主鍵,但不能直接建立索引,也沒有任何數據的統計信息。
 
2.4 使用場景:小數據量(百條之內) 注意:表變量不受事務的約束,下面的DEMO會演示。
複製代碼
--DEMO 表變量
declare @tb table(col1 int primary key,col2 varchar(10)) begin tran insert into @tb select 1,'aa' rollback tran --雖然上面回滾了事務,但仍是會返回1條記錄 select * from @tb begin tran update @tb set col2= 'bb' where col1 = 1 rollback tran --返回的數據顯示,update操做成功,根本沒有回滾 select * from @tb
複製代碼

 

三、CTE
3.1 內涵 
CTE,就是通用表表達式。 3.2 存儲
產生的數據通常存儲在內存,不會持久化存儲。
也能夠持久化:
複製代碼
;with cte  
as 
(  
select 1 as v,'aa' as vv  
union all 
select 2,'bb' 
)  
   
--把cte的數據存儲在tb_cte表  
select * into tb_cte  
from cte  
   
select * from tb_cte;  
     
--運用cte,刪除數據  
;with cte_delete  
as 
(  
select * from tb_cte  
)  
   
delete from cte_delete where V = 1  
   
--返回1條數據,另外一條已刪除  
select * from tb_cte
複製代碼

固然,在實際運行時,有些部分,好比假脫機,會把數據存儲在tempdb的worktable、workfile中,另外,一些大的hash join和排序操做,也會把中間數據存儲在tempdb。數據庫

 
3.3 做用域
CTE下第一條SQL

3.4 使用場景
遞歸,SQL邏輯化(重複的部分寫到CTE裏面,能減小SQL量,增長SQL條理性和可讀性) 注意:SQL邏輯化改寫並不能固定執行計劃(邏輯中間表,實際解析後仍是一個SQL)

3.5 特性
在同一個語句中,一次定義,能夠屢次引用。也能夠定義遞歸語句。其實,本質問題就是,一個語句幾千行,語句太複雜了,SQL Server很難作出最優化的執行計劃,這確實難爲SQL Server了,因此後來就把這個CTE改成,每一小段語句,把結果集經過select into插入到臨時表中,由於臨時表是有統計信息的,這樣最後關聯多個臨時表。對SQL Server而言,如今有了每一個小的結果集的精確的統計信息,那麼就天然能作出更爲精確的執行計劃,執行性能天然上升。
 
CTE遞歸案例
複製代碼
--目的:經過傳入ParentId(=5),返回該記錄的全部子節點數據
IF OBJECT_ID('DiGui','U') IS NOT NULL DROP TABLE DiGui CREATE TABLE DiGui( Id INT, ParentId int ) INSERT INTO dbo.DiGui ( Id, ParentId ) select 4 ,0 union select 5 ,0 union select 7 ,0 union select 2 ,1 union select 8 ,5 union select 15 ,5 union select 9 ,7 union select 14 ,11 union select 30 ,15 union select 23 ,15 union select 41 ,18 union select 104, 23 union select 42 ,30 union select 39 ,30 union select 53 ,39 union select 67 ,39 union select 88 ,39 union select 107, 39 ;with temp ( [Id], [parentid]) as ( select Id, parentid FROM DiGui WHERE [parentid] = 5 union all select a.Id, a.parentid from DiGui a inner join temp b ON a.[parentid] = b.[Id] ) select * from temp
複製代碼
相關文章
相關標籤/搜索