轉載自:http://www.cnblogs.com/hliq/archive/2011/06/21/2087152.html
臨時表與永久表相似,但臨時表存儲在 tempdb 中,當不再使用時會自動刪除。
臨時表有兩種類型:本地和全局。它們在名稱、可見性以及可用性上有區別。本地臨時表的名稱以單個數字符號 (#) 打頭;它們僅對當前的用戶連接是可見的;當用戶從 SQL Server 實例斷開連接時被刪除。全局臨時表的名稱以兩個數字符號 (##) 打頭,創建後對任何用戶都是可見的,當所有引用該表的用戶從 SQL Server 斷開連接時被刪除。
例如,如果創建了 employees 表,則任何在數據庫中有使用該表的安全權限的用戶都可以使用該表,除非已將其刪除。如果數據庫會話創建了本地臨時表 #employees,則僅會話可以使用該表,會話斷開連接後就將該表刪除。如果創建了 ##employees 全局臨時表,則數據庫中的任何用戶均可使用該表。如果該表在您創建後沒有其他用戶使用,則當您斷開連接時該表刪除。如果您創建該表後另一個用戶在使用該 表,則 SQL Server 將在您斷開連接並且所有其他會話不再使用該表時將其刪除。
臨時表
臨時表存儲在TempDB數據庫中,所有的使用此SQL Server 實例的用戶都共享這個TempDB,因爲我們應該確保用來存儲TempDB數據庫的硬盤有足夠的空間,以使之能夠自己的增長.最好能夠存儲在一個擁有獨立 硬盤控制器上.因爲這樣不存在和其它的硬盤I/O進行爭用.
我們很多程序員認爲臨時表非常危險,因爲臨時表有可能被多個連接所共享.其實在SQL Server中存在兩種臨時表:局部臨時表和全局臨時表,局部臨時表(Local temp table)以#前綴來標識,並且只能被創建它的連接所使用.全局臨時表(Global temp table)以##前綴來進行標識,並且可以和其它連接所共享.
局部臨時表
局部臨時表不能夠被其它連接所共享的原因其實是在SQL Server 2000中自動爲局部臨時表的表名後面加上了一個唯一字符來標識.如:
CREATE TABLE [#DimCustomer_test]
(
[CustomerKey] [int]
, [FirstName] [nvarchar](50)
,[MiddleName] [nvarchar](50)
,[LastName] [nvarchar](50)
)
現在我們來查看一下TempDB中 sysobjects表,我們會發現我們新創建的臨時表#DimCustomer_test已經被加上了後綴:
USE TempDB
GO
SELECT name FROM sysobjects WHERE name LIKE ’%DimCustomer%’
the Result is:
name
#DimCustomer_test___________________________________________________________________________________________________000000000005
全局臨時表
下面我們來看一下全局臨時表:
CREATE TABLE [##DimCustomer_test]
(
[CustomerKey] [int]
, [FirstName] [nvarchar](50)
,[MiddleName] [nvarchar](50)
,[LastName] [nvarchar](50)
)
現在我們來查看一下TempDB中 sysobjects表,我們會發現我們新創建的臨時表##DimCustomer_test沒有被加上了後綴:
USE TempDB
GO
SELECT name FROM sysobjects WHERE name LIKE ’%DimCustomer%’
The Result are:
#DimCustomer_test___________________________________________________________________________________________________000000000005
##DimCustomer_test
--Drop test temp tables
DROP TABLE [##DimCustomer_test]
DROP TABLE [#DimCustomer_test]
可以看到我們剛纔創建的全局臨時表名字並沒有被加上標識.
表變量
表變量和臨時錶針對我們使用人員來說並沒有什麼不同,但是在存儲方面來說,他們是不同的,表變量存儲在內存中.所以在性能上和臨時表相比會更好些!
另一個不同的地方是在表連接中使用表變量時,要爲此表變量指定別名.如:
USE AdventureWorksDW
GO
DECLARE @DimCustomer_test TABLE
(
[CustomerKey] [int]
, [FirstName] [nvarchar](50)
,[MiddleName] [nvarchar](50)
,[LastName] [nvarchar](50)
)
---insert data to @DimCustomer_test
INSERT @DimCustomer_test
(
[CustomerKey]
, [FirstName]
,[MiddleName]
,[LastName]
)
SELECT
[CustomerKey]
, [FirstName]
,[MiddleName]
,[LastName]
FROM DimCustomer
SELECT [@DimCustomer_test].CustomerKey,SUM(FactInternetSales.OrderQuantity)
FROM @DimCustomer_test INNER JOIN FactInternetSales ON
@DimCustomer_test.CustomerKey = FactInternetSales.CustomerKey
Group BY CustomerKey
Result:
Server: Msg 137, Level 15, State 2, Line 32
Must declare the variable ’@DimCustomer_test’.
如果我們對上面的查詢進行更改,對查詢使用別名(並且找開IO):
-----in the follow script,we used the table alias.
DECLARE @DimCustomer_test TABLE
(
[CustomerKey] [int]
, [FirstName] [nvarchar](50)
,[MiddleName] [nvarchar](50)
,[LastName] [nvarchar](50)
)
INSERT @DimCustomer_test
(
[CustomerKey]
, [FirstName]
,[MiddleName]
,[LastName]
)
SELECT
[CustomerKey]
, [FirstName]
,[MiddleName]
,[LastName]
FROM DimCustomer
SELECT t.CustomerKey,f.OrderQuantity
FROM @DimCustomer_test t INNER JOIN FactInternetSales f ON
t.CustomerKey = f.CustomerKey
where t.CustomerKey=13513
表變量在批處理結束時自動被系統刪除,所以你不必要像使用臨時表表一樣顯示的對它進行刪除.
表變量主要開銷系統的內存,而臨時表則使用tempdb。對於小數據量的中間數據存儲,可以使用表變量,而當需要臨時保存的數據量很龐大時,建議使用臨時表。具體使用表變量還是臨時表,可以根據系統的運行狀況來調整。
====================================================
例如,如果創建名爲 employees 的表,則任何人只要在數據庫中有使用該表的安全權限就可以使用該表,除非它已刪除。如果創建名爲 #employees 的本地臨時表,只有您能對該表執行操作且在斷開連接時該表刪除。如果創建名爲 ##employees 的全局臨時表,數據表中的任何用戶均可對該表執行操作。如果該表在您創建後沒有其他用戶使用,則當您斷開連接時該表刪除。如果該表在您創建後有其他用戶使 用,則 SQL Server在所有用戶斷開連接後刪除該表。
=====================================================
非索引視圖只是一個定義, 不存儲數據, 查詢的時候才從基礎表拿數據
索引視圖會存儲數據
索引視圖和臨時表的數據都存儲在硬盤
其中索引視圖的數據存儲在視圖所在的數據庫文件中
臨時表的數據存儲在tempdb這個數據庫文件中
問題 1:爲什麼在已經有了臨時表的情況下還要引入表變量?
解答 1:與臨時表相比,表變量具有下列優點: • 如 SQL Server 聯機叢書“表”(Table) 一文中所述,表變量(如局部變量)具有明確定義的範圍,在該範圍結束時會自動清除這些表變量。
• 與臨時表相比,表變量導致存儲過程的重新編譯更少。
• 涉及表變量的事務僅維持表變量上更新的持續時間。因此,使用表變量時,需要鎖定和記錄資源的情況更少。因爲表變量具有有限的範圍並且不是持久性數據庫的一部分,所以事務回滾並不影響它們。
問題 2:如果說使用表變量比使用臨時表導致存儲過程的重新編譯更少,這意味着什麼?
解答 2:下面的文章討論了重新編譯存儲過程的一些原因:
243586 (http://support.microsoft.com/kb/243586/) 存儲過程重新編譯的疑難解答
“由於某些臨時表操作引起的重新編譯”一節還列出了爲避免一些問題(例如使用臨時表導致重新編譯)而需要滿足的一些要求。這些限制不適用於表變量。
表變量完全獨立於創建這些表變量的批,因此,當執行 CREATE 或 ALTER 語句時,不會發生“重新解析”,而在使用臨時表時可能會發生“重新解析”。臨時表需要此“重新解析”,以便從嵌套存儲過程引用該表。表變量完全避免了此問題,因此存儲過程可以使用已編譯的計劃,從而節省了處理存儲過程的資源。
問題 3:表變量有哪些缺陷?
解答 3:與臨時表相比,它存在下列缺陷: • 在表變量上不能創建非聚集索引(爲 PRIMARY 或 UNIQUE 約束創建的系統索引除外)。與具有非聚集索引的臨時表相比,這可能會影響查詢性能。
• 表變量不像臨時表那樣可以維護統計信息。在表變量上,不能通過自動創建或使用 CREATE STATISTICS 語句來創建統計信息。因此,在大表上進行復雜查詢時,缺少統計信息可能會妨礙優化器確定查詢的最佳計劃,從而影響該查詢的性能。
• 在初始 DECLARE 語句後不能更改表定義。
• 表變量不能在 INSERT EXEC 或 SELECT INTO 語句中使用。
• 表類型聲明中的檢查約束、默認值以及計算所得的列不能調用用戶定義的函數。
• 如果表變量是在 EXEC 語句或 sp_executesql 存儲過程外創建的,則不能使用 EXEC 語句或 sp_executesql 存儲過程來運行引用該表變量的動態 SQL Server 查詢。由於表變量只能在它們的本地作用域中引用,因此 EXEC 語句和 sp_executesql 存儲過程將在表變量的作用域之外。但是,您可以在 EXEC 語句或 sp_executesql 存儲過程內創建表變量並執行所有處理,因爲這樣表變量本地作用域將位於
EXEC 語句或 sp_executesql 存儲過程中。
問題 4:與臨時表或永久表相比,表變量的僅存在於內存中的結構保證了更好的性能,是否因爲它們是在駐留在物理磁盤上的數據庫中維護的?
解答 4:表變量不是僅存在於內存中的結構。由於表變量可能保留的數據較多,內存中容納不下,因此它必須在磁盤上有一個位置來存儲數據。與臨時表類似,表變量是在 tempdb 數據庫中創建的。如果有足夠的內存,則表變量和臨時表都在內存(數據緩存)中創建和處理。
問題 5:必須使用表變量來代替臨時表嗎?
解答 5:答案取決於以下三個因素: • 插入到表中的行數。
• 從中保存查詢的重新編譯的次數。
• 查詢類型及其對性能的指數和統計信息的依賴性。
在某些情況下,可將一個具有臨時表的存儲過程拆分爲多個較小的存儲過程,以便在較小的單元上進行重新編譯。
通常情況下,應儘量使用表變量,除非數據量非常大並且需要重複使用表。在這種情況下,可以在臨時表上創建索引以提高查詢性能。但是,各種方案可能互不相同。Microsoft 建議您做一個測試,來驗證表變量對於特定的查詢或存儲過程是否比臨時表更有效。