--==========================================================================
在博客園看到一篇文章《SQLServer Temp tables 數據疑問》,文章中問道在沒有任何負載情況下,還有大量的臨時表,這是為什么?
--==========================================================================
讓我們來實驗探索下
首先選擇任何一個用戶數據庫,執行以下腳本:
CREATE PROCEDURE USP_TempTableTest AS BEGIN SET NOCOUNT ON; CREATE TABLE #TB1(C11 INT,C22 INT) INSERT INTO #TB1 SELECT 1,1 SELECT * FROM #TB1 END GO EXEC USP_TempTableTest
按照通用的理解,存儲過程中的臨時表會在調用中創建,在存儲過程調用結束后釋放,存儲過程執行結束后,我們不應該在tempdb中找到#TB1開頭的臨時表。
讓我們來檢查下
use tempdb go --====================================== --查看臨時表的列 SELECT OBJECT_NAME(OBJECT_ID) AS ObjName, * FROM SYS.all_columns WHERE OBJECT_NAME(OBJECT_ID) LIKE '%#%'
運行以上代碼,可以很容易找到:
列名C11和C22和我們存儲過程中定於的臨時表列名一樣,只是換了個馬甲而已,別告訴我換了馬甲你們就不認識”它“咯
--================================================================
解釋:
上面看到的#A2206DOC這個臨時表並不是我們存儲過程中使用到的#TB1,但是但是兩者存在一定關聯。想象一下,每次存儲過程執行,都需要創建和釋放臨時表,而創建和釋放臨時表又涉及到修改很多系統表的數據,而如果緩存這個臨時表,那么下一次調用存儲過程時,就避免創建和釋放臨時表所照成的資源消耗,從而達到一定的性能提升。
專業解釋:
SQL Server刪除一個臨時對象時,不移除該對象的條目,當再次使用時,就無須重新創建臨時對象,SQL Server為臨時對象緩存一個數據頁和一個IAM頁,並回收剩余頁,如果臨時表的大小超過8MB,回收會異步進行。
--==================================================================
問題1: 多個存儲過程並發調用的時候怎么辦?
當並發調用時,會生成多個類似的臨時表”緩存“以供調用,並保證一個臨時表”緩存“在一個時間點內只能被一個回話執行的存儲過程訪問到,在訪問結束后,會清理該臨時表”緩存“的數據,然后供下一個回話使用。
問題2: 什么樣的臨時表會被”緩存“
當然不是所有臨時表都會被緩存,需要滿足一定的條件:
1. 沒有創建命名約束
2. 臨時對象在創建后沒有執行影響臨時表的數據定義語言DDL操作(如創建索引和創建統計)
3. 沒有使用動態SQL創建臨時對象
4. 臨時對象被創建在另一個對象的內部,如存儲過程、觸發器、用戶自定義函數或臨時對象是一個用戶自定義表值函數的分會表
--=====================================================================
依舊妹子引狼(最近小忙,不能保證妹子質量,勿怪)