Tempdb就像Sqlserver的臨時倉庫,各式各樣的對象,數據在里面進行頻繁計算,操作.大量的操作使得tempdb可能面臨很大壓力,tempdb中緩存的設計就是為了緩解這些壓力.這次就為大家介紹下tempdb的緩存機制.
在介紹緩存機制前,先簡單了解一下TempDB對象
一般我們把tempdb對象分為兩種類型用戶對象和內部對象.用戶對象指通過顯式T-sql來創造的對象(如臨時表),內部對象指通過隱式T-sql創建的對象(Worktables)
注:在引入版本控制后,也可以此單獨分類(DMV sys.dm_db_file_space_usage中單獨列出)
用戶對象
臨時表
表變量(包含表值函數返回值及表值參數)
臨時存儲過程
用戶自定義對象
用戶在線(Online)創建索引空間
內部對象
Sorts(排序溢出)
Worktables(checkdb,游標,Merge joins,假脫機,並行查詢交換溢出,LOB對象等)
Workfiles(hash join 溢出)
Version store(版本行控制)
查看對象使用情況
當tempdb數據文件很大或者有異常時,我們可以查看相應的使用情況.如何查看,沄劍的Blog中如何查看某個查詢用了多少TempDB空間有詳細腳本.
Tempdb緩存機制
Tempdb中的眾多對象緩存機制不盡相同,其中一些操作(如Sort)采用內部的機制,對用戶是不可控的,這里我們主要介紹常用對象臨時表/表變量(也是經常引發問題)的緩存機制.
臨時表緩存機制(#t)
只有使用存儲過程,觸發器,Functions才能緩存
以plan cache的形式緩存一個IAM頁和一個DatePage頁
禁止Create后使用DDL操作
禁止命名約束
可以看出臨時表的緩存是以proc執行計划緩存的形式實現的.所以batch,動態sql是無法緩存的.值得注意的是既然是執行計划緩存,我們就不能在proc中加WITH RECOMPILE關鍵字.
注意:緩存對象時局部臨時表,不包括全局臨時表.
我們通過一個簡單的實例來分析下緩存實現.
首先我們來看下一般batch的操作(非緩存)執行兩次,觀察日志情況如圖1-1
batch create code
use tempdb go checkpoint go create table #t ( id int ) insert into #t select 1 drop table #t select Operation,CONTEXT,[Transaction ID],AllocUnitId,AllocUnitName,[Page ID],[Transaction Name],Description from fn_dblog(null,null)
圖1-1
實際上我們可以看出第一次和第二次執行的日志記錄情況是相同的.
再來看下proc方式
proc code
use tempdb go checkpoint go create proc p_tstcache as create table #t ( id int ) insert into #t select 1 exec p_tstcache------第一次執行后觀察日志記錄如圖1-2 select Operation,CONTEXT,[Transaction ID],AllocUnitId,AllocUnitName,[Page ID],[Transaction Name],Description from fn_dblog(null,null) checkpoint go exec p_tstcache------第二次執行后觀察日志記錄信息如圖1-3 select Operation,CONTEXT,[Transaction ID],AllocUnitId,AllocUnitName,[Page ID],[Transaction Name],Description from fn_dblog(null,null)
圖1-2
圖1-3
可以看到當存儲過程第二次執行時使用了緩存,日志記錄數明顯減少.使用完成后繼續緩存。
緩存的益處
我們通過一個簡單的壓力測試來看下緩存的效果.
我們使用sqlquerystress開100的threads分別執行1000次看下batch,proc,proc中create后ddl的效果.(感興趣的朋友可以觀察相應的計數器 temp tables creation rate) 圖1-4
注意:預先設定好tempdb數據日志文件大小,避免因為文件增長帶來的測試偏差.
Code 1 batch
create table #t (id int)
Drop table #t
Code2 proc
Create proc p_tstcache As create table #t (id int)
Code 3 proc ddl after create script
create proc p_tstcache_ddl as create table #t (id int) Create index ix_id on #t(id) ----ddl after create
圖1-4
可以看到因為緩存機制,在一些應用頻繁創建臨時表的實例中我們可以通過proc中完成臨時表的構建從而緩解競爭.但應注意proc 臨時表cache的限制.
關於表變量.
表變量的緩存機制與臨時表相同(注: 表值參數不支持緩存)
表變量是不能創建索引的,但可以有個默認約束
表變量沒有統計信息
表變量不支持事務
關於Proc中顯式drop臨時表.
微軟聲稱proc中顯式drop臨時表並不受create后DDL的影響,但在現實生產環境中的情況,顯式drop還是有一定影響的.況且proc執行完成后字自動緩存處理,沒必要顯式drop.
關於臨時表/表變量緩存應用
通過上面的實例我們可以看到,如果要利用proc緩存cache是有不少限制的.現實生產環境中我們有可能使用到臨時表(表變量)需要創建索引以提高查詢效率.這時就需要我們來權衡.實際上高並發查詢中使用數據量較大的臨時表此時我們可以在創建臨時表的腳本中一並完成索引的創建.但高並發的大臨時表下的壓力會是創建過程嗎?
結語:有時候DBA的工作的確是手藝活,需要不停的打磨權衡.在業務穩定的情形下如果我們無法調整硬件環境,就需要我們打造業務所需的合理平衡.