1、臨時表
1.1 臨時表包括:以#開頭的局部臨時表,以##開頭的全局臨時表。
1.2 存儲
不管是局部臨時表,還是全局臨時表,都會放存在tempdb數據庫中。
1.3 作用域
局部臨時表:對當前連接有效,只在創建它的存儲過程、批處理、動態語句中有效,類似於C#語言中局部變量的作用域。
全局臨時表:在所有連接對它都結束引用時,會被刪除,對創建者來說,斷開連接就是結束引用;對非創建者,不再引用就是結束引用。
但最好在用完后,就通過drop table 語句刪除,及時釋放資源。
1.4 特性
和普通的表一樣,能定義約束,能創建索引,最關鍵的是有數據分布的統計信息,這樣有利於優化器做出正確的執行計划,但同時它的開銷和普通的表一樣,一般適合數據量較大的情況。有一個非常方便的select ... into 的用法,這也是一個特點。
1.5
使用場景:
數據量小直接當做中間表使用,數據量較大可以通過優化提高查詢效率,對於復雜的查詢可以將中間結果放在臨時表中以固化執行計划(專治執行計划走錯)
2、表變量
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
3、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