1. 程式人生 > >效能調優之:快取

效能調優之:快取

在執行任何查詢時,SQL Server都會將資料讀取到記憶體,資料使用之後,不會立即釋放,而是會快取在記憶體Buffer中,當再次執行相同的查詢時,如果所需資料全部快取在記憶體中,那麼SQL Server不會產生Disk IO操作,立即返回查詢結果,這是SQL Server的效能優化機制。

一,主要的記憶體消費者(Memory Consumer)

1,資料快取(Data Cache)

Data Cache是儲存資料頁(Data Page)的緩衝區,當SQL Server需要讀取資料檔案(File)中的資料頁(Data Page)時,SQL Server會把整個Page都調入記憶體(記憶體中的一個Page叫做buffer),Page是資料訪問的最小單元。

當用戶修改了某個Page上的資料時,SQL Server 會先在記憶體中修改Buffer,但是不會立即將這個資料葉寫回硬碟,而是等到CheckPoint或lazy Writer程序執行時集中處理。當用戶讀取某個Page後,如果SQL Server沒有記憶體壓力,它不會在記憶體中刪除這個Page,因為記憶體中的資料頁始終存放著資料的最新狀態,如果有其他使用者使用這個Page,SQL Server 不需要從硬碟中讀取一次,節省語句執行的時間。理想情況是SQL Server將使用者需要訪問的所有資料都快取在記憶體中,SQL Server 永遠不需要去硬碟讀取資料,只需要在CheckPoint 或 lazy Write執行時把修改過的頁面寫回硬碟即可

2,查詢計劃快取(Query Plan Cache)

儲存查詢語句和儲存過程的執行計劃,以供重用,而不需要重新編譯(Compile),因為編譯查詢語句產生執行計劃是一個非常耗費資源的過程。

二,檢視記憶體消耗

在SQL Server中,只有記憶體書記員(Memory Clerk)能夠分配記憶體,Memory Clerk會記錄已經分配記憶體的數量,任何一個需要使用記憶體的物件,必須建立自己的Memory Clerk,並使用該Memory clerk來分配記憶體。

1,檢視Memory clerk分配的記憶體量

select memory_node_id, 
    type,
    pages_kb,
    virtual_memory_reserved_kb,
    virtual_memory_committed_kb,
    shared_memory_reserved_kb,
    shared_memory_committed_kb,
    page_size_in_bytes
from sys.dm_os_memory_clerks where type = 'MEMORYCLERK_SQLQERESERVATIONS'
View Code

對於記憶體結點64,只在DAC中使用。

2,統計Memory Clerk分配的記憶體總量

select mc.type,mc.name,
    sum(mc.pages_kb) as AllocatedPages_KB,
    sum(mc.virtual_memory_reserved_kb) as VM_Reserved_KB,
    sum(mc.virtual_memory_committed_kb) as VM_Committed_KB,
    --sum(mc.shared_memory_reserved_kb) as ShareMem_Reserved_KB,
    --sum(mc.shared_memory_committed_kb) as ShareMem_Committed_KB,
    max(mc.page_size_in_bytes)/1024 as SinglePageSize_KB
from sys.dm_os_memory_clerks mc
group by mc.type,mc.name
order by AllocatedPages_KB desc,mc.type,mc.name
View Code

消耗記憶體較大的Clerk是:

  • MEMORYCLERK_SQLBUFFERPOOL:基本是Buffer Pool中page的大小
  • OBJECTSTORE_LOCK_MANAGER:鎖結構使用的記憶體,當發生嚴重的鎖阻塞時,這表明系統中,儲存大量鎖,造成鎖管理佔用大量的記憶體;
  • CACHESTORE_OBJCP:觸發器和儲存過程等模組(Module)的執行計劃佔用的快取空間;
  • CACHESTORE_SQLCP:動態TSQL語句,即席(Adhoc)查詢和預編譯(Prepared) TSQL的執行計劃快取;
  • CACHESTORE_COLUMNSTOREOBJECTPOOL:列儲存索引(ColumnStore Index)佔用的快取

3,檢視快取中的資料頁

當資料頁從硬碟讀取到記憶體之後,該資料頁被複制到緩衝池(Buffer Pool),供SQL Server重用。每個快取的資料頁都有一個快取描述器(Buffer Descriptor),使用者唯一標識記憶體中的資料頁,在SQL Server例項中快取的每一個數據頁,都能從 sys.dm_os_buffer_descriptors 檢視快取描述的資訊。

select DB_NAME(bd.database_id) as dbname,
    OBJECT_NAME(p.object_id) as ObjectName,
    i.name as IndexName,
    count(0) as BufferCounts,
    sum(bd.free_space_in_bytes)/1024 as TotalFreeSpace_KB,
    cast(sum(bd.free_space_in_bytes)/(8*1024.0)/count(0) as decimal(10,4))*100 as FreeSpaceRatio,
    sum(cast(bd.is_modified as int)) as TotalDirtyPages,
    sum(bd.row_count) as TotalRowCounts
from sys.allocation_units au 
inner join sys.dm_os_buffer_descriptors bd
    on au.allocation_unit_id=bd.allocation_unit_id
inner join sys.partitions p 
    on au.container_id=p.hobt_id
inner join sys.indexes i 
    on p.object_id=i.object_id and p.index_id=p.index_id
inner join sys.objects o
    on p.object_id=o.object_id
where bd.database_id=DB_ID(N'database_name')
    and o.type<>N'S'
group by bd.database_id,p.object_id,i.name 
order by BufferCounts desc,dbname,ObjectName
View Code

4,檢視計劃快取

產生執行計劃是十分消耗CPU資源的,SQL Server會在記憶體的Plan Cache中儲存每個查詢計劃(Query Plan),及其佔用的記憶體空間,重用次數等資訊。

select cp.objtype,cp.cacheobjtype,
    sum(cp.size_in_bytes) as TotalSize_B,
    COUNT(cp.bucketid) as CacheCounts,
    sum(cp.refcounts) as TotalRefCounts,
    sum(cp.usecounts) as TotalUseCounts
from sys.dm_exec_cached_plans cp 
group by cp.objtype,cp.cacheobjtype
order by TotalSize_B desc
View Code

三,清空快取

在調優儲存過程效能時,清空快取是必需的,緩衝池(Buffer Pool)是SQL Server的快取管理器,包含了SQL Server的絕大部分快取資料(Cache),例如,執行計劃快取(Plan cache),資料快取(Data cache)等。

清空快取常用的命令有如下三個:

CHECKPOINT
DBCC DROPCLEANBUFFERS DBCC FREEPROCCACHE

Checkpoint和DBCC DROPCLEANBUFFERS 用於清理資料快取(Data Cache)中的髒頁(dirty pages)和乾淨頁(clean pages),而DBCC FREEPROCCACHE 用於清空所有的計劃快取(Plan Cache)。

1,清空資料快取

checkpoint 用於將髒頁(Dirty Pages)寫入硬碟,髒頁(Dirty Pages)是指資料頁讀入快取後,被修改過,導致記憶體中資料頁和硬碟中的資料頁中的內容不同;乾淨頁(Clean Pages)是指資料頁被讀入快取後,沒有被修改過,所以,記憶體中的資料頁和硬碟中的資料頁中的內容相同。不管是Dirty pages 還是 Clean pages 都是Data Cache,在效能調優時,都必須從記憶體中清理掉,否則,查詢效能將忽略掉資料從硬碟載入到記憶體的IO消耗,影響查詢語句的執行情況。

CHECKPOINT 命令用於產生冷快取(Cold buffer Cache),該命令將當前資料庫產生的所有髒頁寫入到硬碟,並清理記憶體buffer;在執行CHECKPOINT命令之後,執行 DBCC DROPCLEANBUFFERS 用於從緩衝池中清空所有的乾淨頁。

在效能測試時,使用DBCC DROPCLEANBUFFERS從SQLSERVER的資料快取池中清除所有的clean快取資料,需要注意的是該命令只移走乾淨的快取,不移走髒快取。因此,在執行這個命令前,應該先執行CheckPoint,將所有髒頁寫入磁碟,這樣在執行DBCC RROPCLEANBUFFERS 時,可以保證所有的資料快取被清理,而不是其中的一部分。

2,清空計劃快取

計劃快取(Plan Cache)用於快取查詢語句的執行計劃,每一條查詢語句在執行之後,其查詢計劃都會快取Plan Cache中。在產品環境中,不要輕易清理掉Plan Cache。如果檢測到某個Plan Cache產生引數嗅探問題,導致效能十分低下,推薦修改查詢語句,重新編譯儲存過程,以單獨重新整理該SP的計劃快取。

DBCC FREEPROCCACHE [ ( { plan_handle | sql_handle} ) ]

計劃快取,之前叫做過程快取(procedure cache),執行DBCC FREEPROCCACHE 命令,釋放所有的計劃快取,這回導致儲存過程,AdHoc 查詢等查詢必須重新編譯,產生新的計劃快取。

四,強制重新編譯執行計劃

修改儲存過程,觸發器等模組(Module)能夠使其執行計劃重新編譯,除此之外,還有其他方法,能夠強制重新編譯執行計劃

1,標記,下次重新編譯

使用該儲存過程,標記一個執行模組(SP,Trigger,User-Defined Function)在下次執行時,重新編譯執行計劃

sys.sp_recompile [ @objname = ] 'object'

2,不復用執行計劃

在建立儲存過程時,使用WITH RECOMPILE 選項,在每次執行SP時,都重新編譯,使用新的執行計劃。

CREATE PROCEDURE dbo.usp_procname 
    @Parameter_Name varchar(30) = 'Parameter_default_value'
WITH RECOMPILE

3,執行時重新編譯

在執行儲存過程時,重新編譯儲存過程的執行計劃

exec dbo.usp_procname @Parameter_name='Parameter_value' 
WITH RECOMPILE

4,語句級別的重新編譯

在SP中,使用查詢選項 option(recompile),只重新編譯該語句級別的執行計劃

select column_name_list
from dbo.tablename
option(recompile)

SQL Server在執行查詢之後,查詢提示(RECOMPILE)指示儲存引擎將計劃快取拋棄,在下次執行儲存過程時,強制查詢優化器重新編譯,生成新的執行計劃。在重新編譯時,SQL Server 優化器使用當前的變數值生成新的計劃快取。

附:

冷快取,熱快取,髒快取和乾淨快取名詞解釋:

  • 淨快取頁(Clean Buffer) 是指記憶體中未被修改的資料頁,DBCC DROPCLEANBUFFERS 用於從緩衝池(Buffer Pool)移除乾淨頁,釋放Buffer。
  • 髒快取頁(Dirty Buffer)是指資料頁在記憶體中被修改,但是還沒有寫入到硬碟中,導致硬碟中的資料不同於記憶體,通常情況下,髒頁通過CHECKPOINT程序來自動同步,CHECKPOINT 將髒頁資料寫入到硬碟中,使記憶體和硬碟檔案中的資料保持一致,能夠減少資料還原的時間。
  • 冷快取頁(Cold Buffer)是指,在資料處理階段,最近沒有被使用的快取頁。
  • 熱快取頁(Hot Buffer)是指,在資料處理階段,最近經常被使用的快取頁。

參考文件:

Recompile a Stored Procedure

What is a COLD, DIRTY or CLEAN Buffer