收集的SQL Server性能相关资料
這是本人在工作中整理的關于SQL Server性能相關資料,便于隨時查閱
目錄
性能監視器指標
內存問題診斷
偵測 CPU 壓力
磁盤相關
內存
Memory Clerks
Buffer Pool
Plan Cache
CPU
線程
硬件信息
等待信息
SOS_SCHEDULER_YIELD等待
CXPACKET等待
資源消耗統計
I/O
讀寫信息
常見問題
索引
MDV
統計?
日志
WRITELOG等待
LOGBUFFER等待
小結
相關SQL
?
?
性能監視器指標
內存問題診斷
| Memory Manager\Total Server Memory(KB) | Buffer Pool的大小 | ? |
| Memory Manager\Target Server Memory(KB) | 表示空閑的Buffer Pool大小。 Total和Target的值應該盡可能相同, 如果Total明顯小于Target, 可能意味著出現了內存壓力,需要更深入地研究。 | ? |
| Memory Manager\Granted Workspace Memory( KB) | 當前查詢正在使用的總內存大小。 Workspace:指在查詢過程中,進行hash和排序操作時,臨時存儲數據的結果集所用的內存。如果在執行計劃中看到出現了hash或者sort操作符,那么就表示會使用這部分的內存完成處理。 Memory Grants:已經分配給查詢的那部分內存。 可以用過 sys. dm_exec_query_memory_grants查看。 另外, RESOURCE_ SEMAPHORE 等待狀態是針對 memory grants 的,所以如果在sys. dm_ os_ wait_ stats這個DMV中看到這個等待類型存在很久,并且處于前幾位,可能需要檢查內存是否足夠快。 如果內存授予(memory grants)太久,會導致查詢超時,可以使用SQL trace或者執行計劃查看是否存在hash或者sort warning這些信息。 | ? |
| Memory Manager\Maximum Workspace Memory( KB) | SQL Server 標記預留給某個查詢的總內存大小。 | ? |
| Memory Manager\Memory Grants Pending | 正在隊列中的內存grants數量。 | >2 |
| Memory Manager\Memory Grants Outstanding | 正在使用的內存grants數量。 | ? |
| Buffer Manager\Buffer Cache Hit Ratio | Percentage of pages that were found in the buffer pool without having to incur a read from disk. | >90% |
| Buffer Manager\Page Life Expectancy | 代表著一個數據存在于Buffer Pool的時間。這個值越長越好,最低時間應該設置為300s。 | >1000,至少為300 |
| Buffer Manager\Page Lookups/sec | 這個計數器用于衡量實例中的請求在buffer pool里面查詢的單獨頁數量。當這個數值很高時,可能意味著不高效的執行計劃,通常需要研究該執行計劃。一般數值很高是因為執行計劃中產生了大量的Page Lookups和Row Lookups。 | Page Lookups: Batch Request<100 |
| Plan Cache\Cache hit Ratio | Ratio between cache hits and lookups | ? |
| Memory:Available Mbytes | 以字節表示的物理內存數量。此內存能立刻分配給一個進程或系統使用。它等于分配給待機(緩存的)、空閑和零分頁列表內存的總和。要獲得內存管理器的詳細解釋,請參閱 MSDN 和/或 Windows Server 2003 Resource Kit 里的系統性能和疑難解答指南章節。 | ? |
| Memory:Page Faults/sec | 每秒鐘出錯頁面的平均數量。由于每個錯誤操作中只有一個頁面出錯,計算單位為每秒出錯頁面數量,因此這也等于頁面錯誤操作的數量。這個計數器包括硬錯誤(那些需要磁盤訪問的)和軟錯誤(在物理內存的其他地方找到的錯誤頁)。許多處理器可以在有大量軟錯誤的情況下繼續操作。但是,硬錯誤可以導致明顯的拖延。 | ? |
| Memory:Pages/sec | 指為解決硬頁錯誤從磁盤讀取或寫入磁盤的速度。這個計數器是可以顯示導致系統范圍延緩類型錯誤的主要指示器。它是 Memory\\Pages Input/sec 和 Memory\\Pages Output/sec 的總和。是用頁數計算的,以便在不用做轉換的情況下就可以同其他頁計數如: Memory\\Page Faults/sec 做比較,這個值包括為滿足錯誤而在文件系統緩存(通常由應用程序請求)的非緩存映射內存文件中檢索的頁。 | ? |
偵測 CPU 壓力
| Access Methods\Forwarded Records/sec。 | 該計數器統計每秒通過正向記錄指針提取的記錄數,這個計數器用于衡量服務器中對Forwarded數據的訪問情況,通常來說,這個值不應該超過Batch Requests/sec的10%。雖然10%不是絕對值,但它是一個警告值。 | ? |
| Access Methods\FreeSpace Scans/sec。 | 這是關于堆表的另外一個計數器。當在堆表中插入數據時,它會標識發生了什么操作。 | ? |
| Access Methods\Full Scans/sec。 | 通過這個計數器可查看Full Scans/sec的值,這個值包含聚集、非聚集索引及堆表。高值意味著查詢存在性能問題,這種情況可能會引起Page Life Expectancy(用于衡量內存壓力的一個主要計數器)的變動,這將加大數據在內存中的存儲時間,并引起I/O問題。 | Batch Requests:Full Scans<1000 |
| Access Methods\Index Searches/sec | 大部分情況下,索引查找會比索引掃描有效,這個計數器顯示出SQL Server實例上發生索引查找的比率,這個值相對于Full Scans/sec來說越高越好。 | Index Searches: Full Scans>1000 |
| Access Methods\Page Splits/sec | 對應于堆上的Forwarded Records,聚集索引上的就是Page Splits了。補充一下,雖然非聚集索引也有這個特性,但是由于沒有聚集索引的表就是堆表,所以堆表上的非聚集索引還是使用的Forwarded Records。Page Splits是一個較消耗資源的操作,而且在拆頁的時候會對原來的頁加上排他鎖,并且會產生碎片,所以應盡可能少用。 | Batch Requests:Page Split>20 |
| Locks(*)\Lock Wait Time(ms) | 相對于前面的計數器,這類計數器更偏重于檢查索引的壓力情況。它可以衡量SQL Server花在索引、表、頁上鎖資源的時間。它沒有可參考值,但是可以作為一個歷史數據,然后用最近監控的數據和這個歷史數據對比,比值應該越低越好。 | ? |
| Locks(*)\Number of Deadlocks/sec。 | 極端情況下,不良的索引設計和過度鎖阻塞會引起死鎖(Deadlocks),這種情況是絕對不能容忍的。 | =0 |
| Processor/%Privileged Time | 花費在執行Windows內核命令上的處理器時間的百分比。 | ? |
| Processor/%User Time | 花費在處理應用程序如SQL Server上的處理器時間百分比。 | ? |
| Process(sqlservr. exe)/%Processor Time | 每個處理器上所有進程的總處理時間。 | ? |
| SQL Statistics\Auto-Param Attempts/sec | Number of auto-parameterization attempts. | ? |
| SQL Statistics\Failed Auto-params/sec | Number of failed auto-parameterizations. | ? |
| SQL Statistics\Batch Requests/sec | Number of failed auto-parameterizations. | ? |
| SQL Statistics\SQL Compilations/sec | Number of SQL compilations. | ? |
| SQL Statistics\SQL Re-Compilations/sec | Number of SQL re-compiles. | ? |
磁盤相關
| Physical Disk\Average Disk sec/Read | Avg. Disk sec/Read 指以秒計算的在此盤上讀取數據的所需平均時間。 | ? |
| Physical Disk\Average Disk sec/Write | Avg. Disk sec/Write 指以秒計算的在此盤上寫入數據的所需平均時間。 | ? |
| Physical Disk\Average Disk Read/Read Queue Length | Avg. Disk Read Queue Length 指讀取請求(為所選磁盤在實例間隔中列隊的)的平均數。 | ? |
| Physical Disk\Average Disk Read/Write Queue Length | Avg. Disk Write Queue Length 指寫入請求(為所選磁盤在實例間隔中列隊的)的平均數。 | ? |
| Physical Disk\Disk Reads/sec | Disk Reads/sec 指在此盤上讀取操作的速率。 | <10ms=沒有性能問題 ·10~20ms=存在問題 ·20~50ms=性能很低 ·>50ms=性能問題嚴重 |
| Physical Disk\Disk Writes/sec | Disk Writes/sec 指在此盤上寫入操作的速率。 | <10ms=沒有性能問題 ·10~20ms=存在問題 ·20~50ms=性能很低 ·>50ms=性能問題嚴重 |
?
內存
Memory Clerks
-- 用于內存緩存的一種機制,
SELECT [type],
?????? memory_node_id,
?????? virtual_memory_reserved_kb,
?????? virtual_memory_committed_kb,
?????? awe_allocated_kb
FROM?? sys.dm_os_memory_clerks
ORDER? BY virtual_memory_reserved_kb DESC
?
Buffer Pool
SQL Server 內存中的最大消耗者。
--每個數據庫緩存大小
SELECT LEFT(CASE database_id
????????????? WHEN 32767 THEN 'ResourceDb'
????????????? ELSE Db_name(database_id)
??????????? END, 20)???????????????????????????????? AS Database_Name,
?????? Count(*)????????????????????????????????????? AS Buffered_Page_Count,
?????? Cast(Count(*) * 8 / 1024.0 AS NUMERIC(10, 2)) AS Buffer_Pool_MB
FROM?? sys.dm_os_buffer_descriptors
GROUP? BY Db_name(database_id),
????????? database_id
ORDER? BY Buffered_Page_Count DESC
?
--當前臟頁數
SELECT Db_name(database_id) AS 'Database',
?????? Count(page_id)?????? AS 'Dirty Pages( KB)'
FROM?? sys. dm_os_buffer_descriptors
WHERE? is_modified = 1
GROUP? BY Db_name(database_id)
ORDER? BY Count(page_id) DESC
?
Plan Cache
--執行計劃緩存
SELECT Count(*)???????????????????????????????????????? AS 'Number of Plans',
?????? Sum(Cast(size_in_bytes AS BIGINT)) / 1024 / 1024 AS 'Plan Cache Size (MB)'
FROM?? sys. dm_exec_cached_plans
?
--查看緩存對象的對應內存數。
SELECT objtype????????????????????????????????????? AS 'Cached Object Type',
?????? Count(*)???????????????????????????????????? AS 'Number of Plans',
?????? Sum(Cast(size_in_bytes AS BIGINT)) / 1048576 AS 'Plan Cache Size (MB)',
?????? Avg(usecounts)?????????????????????????????? AS 'Avg Use Count'
FROM?? sys. dm_exec_cached_plans
GROUP? BY objtype
?
CPU
線程
--當前系統最大線程數
SELECT max_workers_count
FROM?? sys.dm_os_sys_info
?
--當前工作線程
SELECT Count(*)
FROM?? sys.dm_os_workers
?
硬件信息
--NUMA配置
SELECT scheduler_id,
?????? cpu_id,
?????? parent_node_id,
?????? status
FROM?? sys.dm_os_schedulers
?
--得知超線程和核心方面的關系。
SELECT cpu_count???????????????????? AS [Logical(邏輯) CPU Count],
?????? hyperthread_ratio???????????? AS [Hyperthread(超線程) Ratio],
?????? cpu_count / hyperthread_ratio AS [Physical(物理) CPU Count],
?????? physical_memory_kb / 1024???? AS [Physical Memory (MB)]
FROM?? sys. dm_os_sys_info
?
等待信息
--等待類型中等待時間最長的10個類型。
SELECT TOP (10) wait_type,
??????????????? waiting_tasks_count,
??????????????? ( wait_time_ms - signal_wait_time_ms ) AS resource_wait_time,
??????????????? max_wait_time_ms,
??????????????? CASE waiting_tasks_count
????????????????? WHEN 0 THEN 0
????????????????? ELSE wait_time_ms / waiting_tasks_count
??????????????? END??????????????????????????????????? AS avg_wait_time
FROM?? sys.dm_os_wait_stats
WHERE? wait_type NOT LIKE '%SLEEP%'
?????? --去除不相關的等待類型
?????? AND wait_type NOT LIKE 'XE%'
?????? AND wait_type NOT IN
?????????? -- 去除系統類型
?????????? ( 'KSOURCE_WAKEUP', 'BROKER_TASK_STOP', 'FT_IFTS_SCHEDULER_IDLE_WAIT', 'SQLTRACE_BUFFER_FLUSH',
???????????? 'CLR_AUTO_EVENT', 'BROKER_EVENTHANDLER', 'BAD_PAGE_PROCESS', 'BROKER_TRANSMITTER',
???????????? 'CHECKPOINT_QUEUE', 'DBMIRROR_EVENTS_QUEUE', 'SQLTRACE_BUFFER_FLUSH', 'CLR_MANUAL_EVENT',
???????????? 'ONDEMAND_TASK_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'LOGMGR_QUEUE', 'BROKER_RECEIVE_WAITFOR',
???????????? 'PREEMPTIVE_OS_GETPROCADDRESS', 'PREEMPTIVE_OS_AUTHENTICATIONOPS', 'BROKER_TO_FLUSH' )
ORDER? BY wait_time_ms DESC
?
?
SELECT wait_type,
?????? signal_wait_time_ms,
?????? wait_time_ms
FROM?? sys.dm_os_wait_stats
WHERE? wait_time_ms > 0
?????? AND wait_type NOT IN ( 'CLR_SEMAPHORE', 'CLR_AUTO_EVENT', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE',
????????????????????????????? 'SLEEP_TASK', 'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR',
????????????????????????????? 'LOGMGR_QUEUE', 'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',
????????????????????????????? 'BROKER_TO_FLUSH', 'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE',
????????????????????????????? 'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP' )
ORDER? BY signal_wait_time_ms DESC
?
SOS_SCHEDULER_YIELD等待
發生在一個任務自愿放棄當前的資源占用,讓給其他任務使用的時候,就像前面說的離開飲水機讓別人去接水。 現代關系型數據庫管理系統早已支持多個任務同時運行,SQL Server的運行機制之一就是減少runnable的線程等待,也就是說,SQL Server希望盡快運行runnable的線程。它以協同模式運行,在必要的時候,SQL Server會讓出某個資源來給其他線程,通常來說這種情況是臨時的。但是當長期、大量出現這種等待類型的時候,有可能意味著CPU存在壓力,這時候可以檢查這個DMV中的數據:sys.dm_os_schedulers,看看當前有多少runnable的任務在系統中運行。
--當前有多少runnable的任務在系統中運行
SELECT scheduler_id,
?????? current_tasks_count,
?????? runnable_tasks_count,
?????? work_queue_count,
?????? pending_disk_io_count
FROM?? sys.dm_os_schedulers
WHERE? scheduler_id < 255
通常我們需要關注runnable_tasks_count這個列的數據,如果見到長時間存在兩位數的數值(記住是長時間存在),就意味著CPU可能存在壓力,無法應付當前負載。
?
CXPACKET等待
CXPACKET 這種類型有點像平時所說的木桶效應,一個木桶的容量取決于組成木桶最短的那塊木條的長度。如果一個查詢由多個線程組成,那么只有在最慢的那個線程完成之后,整個查詢才會完成。在這種情況下,SQL Server就出現了CXPACKET等待。 CXPACKET是其中一個最常見的并行等待,在多CPU的環境下,這種等待經常會出現。并行執行最重要的目的就是使得運算更快,一個單獨的查詢可以使用多個線程來共同完成,每個線程會單獨處理數據集的一部分。但應該注意的是,某些等待并不總是表示系統性能存在問題,CXPACKET就是其中一種。比如有一家軟件公司,通常會招聘多個開發人員去完成開發工作。但是每天上下班時,總需要一個人一個人串行“打卡”,這時候CXPACKET就會出現在打卡的過程中,因為這個時候必須串行而不是并行。你可能覺得打卡過程中所用的時間是浪費的,但是從整體來說,你雇用更多的人去完成功能開發,理想情況下是可以加快項目的開發進度的,不應該因為打卡這幾秒鐘的浪費而無視他們在一天中對進度的貢獻。 在并行過程中,如果某個線程處于落后狀態,CXPACKET等待狀態就會產生。在上面的例子中,如果你為了移除這種等待狀態而減少雇員,比如只留下一個,那么你整體的項目進度將會嚴重延遲。 但是畢竟出現等待狀態就是表示有一定的資源問題,所以需要針對這種情況進行分析。前面提到過,對問題的分析要全面、整體,并且要區分應用系統類型。
OLTP系統
它的特點是事務數量多,但是正常來說,事務的持續時間不會很久。
如果CXPACKET等待狀態頻繁出現,且持續時間很長,那就意味著性能可能有問題了。
理想情況下事務很短,這時候就沒有必要通過并行運行來提高運行速度了。所以對于這類系統,有一個極端方法(如非必要不要用),即把最大并行度(Max Degree of Parallelism)設為1,強制SQL Server不去使用并行操作,從而減少不必要的資源等待。
OLAP等系統
它的事務量可能不多,但是持續時間往往會很久。
由于事務普遍較長,所以并行操作往往能提高速度和資源利用率。這時候可以讓SQL Server自己控制并行,也就是把最大并行度設為0(即不限制)。
--計劃緩存中存在并行查詢的語句
SELECT TOP 10 p.*,
????????????? q.*,
????????????? qs.*,
????????????? cp.plan_handle
FROM?? sys.dm_exec_cached_plans cp
?????? CROSS apply sys.Dm_exec_query_plan(cp.plan_handle) p
?????? CROSS apply sys.Dm_exec_sql_text(cp.plan_handle) AS q
?????? JOIN sys.dm_exec_query_stats qs
???????? ON qs.plan_handle = cp.plan_handle
WHERE? cp.cacheobjtype = 'Compiled Plan'
?????? AND p.query_plan.value('declare namespace p="http://schemas.microsoft.com/sqlserver/2004/07/showplan";?
??????? max(//p:RelOp/@Parallel)', 'float') > 0
ORDER? BY total_worker_time DESC
OPTION (MAXDOP 1)
?
資源消耗統計
--CPU最高消耗的10個語句
SELECT TOP 10 Substring(ST.text, ( QS.statement_start_offset / 2 ) + 1, ( ( CASE statement_end_offset
????????????????????????????????????????????????????????????????????????????? WHEN -1 THEN Datalength(st.text)
????????????????????????????????????????????????????????????????????????????? ELSE QS.statement_end_offset
??????????????????????????????????????????????????????????????????????????? END - QS.statement_start_offset ) / 2 ) + 1) AS statement_text,
????????????? execution_count,
????????????? total_worker_time / 1000?????????????????????????????????????????????????????????????????????????????????? AS total_worker_time_ms,
????????????? ( total_worker_time / 1000 ) / execution_count???????????????????????????????????????????????????????????? AS avg_worker_time_ms,
????????????? total_logical_reads,
????????????? total_logical_reads / execution_count????????????????????????????????????????????????????????????????????? AS avg_logical_reads,
????????????? last_logical_reads,
????????????? total_logical_writes,
????????????? total_logical_writes / execution_count???????????????????????????????????????????????????????????????????? AS avg_logical_writes,
????????????? last_logical_writes,
????????????? total_elapsed_time / 1000????????????????????????????????????????????????????????????????????????????????? AS total_elapsed_time_ms,
????????????? ( total_elapsed_time / 1000 ) / execution_count??????????????????????????????????????????????????????????? AS avg_elapsed_time_ms,
????????????? last_elapsed_time / 1000,
????????????? qp.query_plan
FROM?? sys.dm_exec_query_stats qs
?????? CROSS APPLY sys.Dm_exec_sql_text(qs.sql_handle) st
?????? CROSS APPLY sys.Dm_exec_query_plan(qs.plan_handle) qp
ORDER? BY total_worker_time DESC
?
--找出使用頻率最高的20%的查詢
SELECT TOP 20 PERCENT cp.usecounts???? AS ' 使用次數',
????????????????????? cp.cacheobjtype? AS ' 緩存類型',
????????????????????? cp.objtype?????? AS [ 對象類型],
????????????????????? st.text????????? AS 'TSQL',
????????????????????? --cp.plan_handle AS ' 執行計劃',
????????????????????? qp.query_plan??? AS ' 執行計劃',
????????????????????? cp.size_in_bytes AS ' 執行計劃占用空間( Byte)'
FROM?? sys.dm_exec_cached_plans cp
?????? CROSS APPLY sys.Dm_exec_sql_text(plan_handle) st
?????? CROSS APPLY sys.Dm_exec_query_plan(plan_handle) qp
ORDER? BY usecounts DESC
?
I/O
讀寫信息
--查看當前數據庫文件中的IO情況
SELECT Db_name(Db_id())?????????????????????????????????????????????????????????????????????????????????? AS [Database Name],
?????? [file_id],
?????? num_of_reads,
?????? num_of_writes,
?????? num_of_bytes_read,
?????? num_of_bytes_written,
?????? Cast(100. * num_of_reads / ( num_of_reads + num_of_writes ) AS DECIMAL(10, 1))???????????????????? AS [# Reads Pct],
?????? Cast(100. * num_of_writes / ( num_of_reads + num_of_writes ) AS DECIMAL(10, 1))??????????????????? AS [# Write Pct],
?????? Cast(100. * num_of_bytes_read / ( num_of_bytes_read + num_of_bytes_written ) AS DECIMAL(10, 1))??? AS [Read Bytes Pct],
?????? Cast(100. * num_of_bytes_written / ( num_of_bytes_read + num_of_bytes_written ) AS DECIMAL(10, 1)) AS [Written Bytes Pct]
FROM?? sys. Dm_io_virtual_file_stats(Db_id(), NULL);
?
--計劃緩存中存儲過程的邏輯寫排名,主要是寫操作的壓力
SELECT p. NAME????????????????? AS [SP Name],
?????? qs. total_logical_writes AS [TotalLogicalWrites],
?????? qs. execution_count,
?????? qs. cached_time
FROM?? sys. procedures AS p
?????? INNER JOIN sys. dm_exec_procedure_stats AS qs
?????????????? ON p.[object_id] = qs. [object_id]
WHERE? qs. database_id = Db_id()
?????? AND qs. total_logical_writes > 0
ORDER? BY qs. total_logical_writes DESC;
?
常見問題
解決PAGEIOLATCH等待
潛在問題
數據從磁盤加載到內存buffer中的時間不會很長,一旦數據進入buffer,提取數據會很快,并且查找過程不會產生任何等待。但是也有特殊情況,如果有10個任務都需要同時請求相同的數據,第一個任務會申請加載數據,其他9個任務都必須等待,直到第一個任務的數據加載完畢為止。如果這時磁盤已經超負荷,那么第一個請求會花費較長的時間。同樣,如果內存不足,緩存在buffer中的數據會過早地被沖刷掉(從buffer中清空),從而引起9個任務再次等待下一輪的加載。
降低PAGEIOLATCH等待
當buffer正在加載和卸載時,都會對其中的數據加上閂鎖。這意味著其他進程必須等待,直到釋放閂鎖且數據依舊存在于buffer中為止??焖俚丶虞d和長時間駐留能最大限度地降低等待,這類等待和其他等待類似,當遇到相關問題時,可以評估下面的方案是否可行。
提升I/O子系統的速度。
當存在內存問題或者壓力出現時也會引起這種等待,檢查內存相關的計數器,查看是否存在內存問題,如果存在,嘗試優化或者改善內存。
將LDF/MDF/tempdb的文件分開存放,減少資源爭用。
檢查文件統計信息,看看高I/O讀寫操作出現在什么文件上。
檢查系統是否有合適的索引,丟失索引和不合理的索引都會造成大面積的掃描,通過添加有效的索引可減少I/O請求,緩解I/O壓力。使用覆蓋索引來替代聚集索引是一個不錯的選擇,可以明顯降低CPU、內存和I/O的壓力(因為一般非聚集索引包含的列都比聚集索引少,聚集索引實際上是全表索引)。
更新統計信息,使SQL Server查詢優化器能選擇最優執行計劃。
檢查下面的性能計數器。
SQL Server:Memory Manager\Memory Grants Pending>2
SQL Server:Memory Manager\Memory Grants Outstanding
SQL Server:Buffer Manager\Buffer Hit Cache Ratio>90%
SQL Server:Buffer Manager\Page Life Expectancy>1000,至少為300
Memory:Available Mbytes Memory:Page Faults/sec ·檢查磁盤相關的計數器。
Average Disk sec/Read Average Disk sec/Write Average Disk Read/Write Queue Lenght
?
索引
MDV
| sys.index_columns | 提供了索引內包含的列,也就是索引鍵。每個鍵一行,通過關聯其他DMV 就可以獲得索引定義的列情況。 |
| sys.xml_indexes | 和sys.indexes 類似,但是主要針對XML 索引。 |
| sys.spatial_indexes | 也和sys.indexes 類似,主要針對spatial 索引。 |
| sys.column_store_dictionaries sys.column_store_segments | 主要用于描述從SQL Server 2012 開始引入的列存儲索引信息。 |
| sys.dm_db_index_physical_stats | 索引碎片 |
| sys.dm_db_missing_index_details | 缺失索引相關 |
| sys.dm_db_missing_index_columns | 缺失索引相關 |
| sys.dm_db_missing_index_group_stats | 缺失索引相關 |
| sys.dm_db_missing_index_groups | 缺失索引相關 |
?
統計?
SELECT '[' + Db_name() + '].[' + su.[name] + '].[' + o.[name]
?????? + ']'????????????????? AS [statement],
?????? i.[name]?????????????? AS [index_name],
?????? ddius.[user_seeks] + ddius.[user_scans]
?????? + ddius.[user_lookups] AS [user_reads],
?????? ddius.[user_updates]?? AS [user_writes],
?????? Sum(SP.rows)?????????? AS [total_rows]
FROM?? sys.dm_db_index_usage_stats ddius
?????? INNER JOIN sys.indexes i
?????????????? ON ddius.[object_id] = i.[object_id]
????????????????? AND i.[index_id] = ddius.[index_id]
?????? INNER JOIN sys.partitions SP
?????????????? ON ddius.[object_id] = SP.[object_id]
????????????????? AND SP.[index_id] = ddius.[index_id]
?????? INNER JOIN sys.objects o
?????????????? ON ddius.[object_id] = o.[object_id]
?????? INNER JOIN sys.sysusers su
?????????????? ON o.[schema_id] = su.[UID]
WHERE? ddius.[database_id] = Db_id() -- current database only
?????? AND Objectproperty(ddius.[object_id], 'IsUserTable') = 1
?????? AND ddius.[index_id] > 0
GROUP? BY su.[name],
????????? o.[name],
????????? i.[name],
????????? ddius.[user_seeks] + ddius.[user_scans]
????????? + ddius.[user_lookups],
????????? ddius.[user_updates]
HAVING ddius.[user_seeks] + ddius.[user_scans]
?????? + ddius.[user_lookups] = 0
ORDER? BY ddius.[user_updates] DESC,
????????? su.[name],
????????? o.[name],
????????? i.[name]
?
--查找未被使用過的索引
SELECT Object_name(i.object_id)????????????????????????????????????? AS table_name,
?????? COALESCE(i.NAME, Space(0))??????????????????????????????????? AS index_name,
?????? ps.partition_number,
?????? ps.row_count,
?????? Cast(( ps.reserved_page_count * 8 ) / 1024.AS DECIMAL(12, 2)) AS size_in_mb,
?????? COALESCE(ius.user_seeks, 0)?????????????????????????????????? AS user_seeks,
?????? COALESCE(ius.user_scans, 0)?????????????????????????????????? AS user_scans,
?????? COALESCE(ius.user_lookups, 0)???????????????????????????????? AS user_lookups,
?????? i.type_desc
FROM?? sys.all_objects t
?????? INNER JOIN sys.indexes i
?????????????? ON t.object_id = i.object_id
?????? INNER JOIN sys.dm_db_partition_stats ps
?????????????? ON i.object_id = ps.object_id
????????????????? AND i.index_id = ps.index_id
?????? LEFT OUTER JOIN sys.dm_db_index_usage_stats ius
??????????????????? ON ius.database_id = Db_id()
?????????????????????? AND i.object_id = ius.object_id
?????????????????????? AND i.index_id = ius.index_id
WHERE? i.type_desc NOT IN ( 'HEAP', 'CLUSTERED' )
?????? AND i.is_unique = 0
?????? AND i.is_primary_key = 0
?????? AND i.is_unique_constraint = 0
?????? AND COALESCE(ius.user_seeks, 0) <= 0
?????? AND COALESCE(ius.user_scans, 0) <= 0
?????? AND COALESCE(ius.user_lookups, 0) <= 0
ORDER? BY Object_name(i.object_id),
????????? i.NAME
?
--寫操作還是遠大于讀操作的索引
SELECT Object_name(ddius.[object_id])??????????????????????????? AS [Table Name],
?????? i.NAME??????????????????????????????????????????????????? AS [Index Name],
?????? i.index_id,
?????? user_updates????????????????????????????????????????????? AS [Total Writes],
?????? user_seeks + user_scans + user_lookups??????????????????? AS [Total Reads],
?????? user_updates - ( user_seeks + user_scans + user_lookups ) AS [Difference]
FROM?? sys.dm_db_index_usage_stats AS ddius WITH ( NOLOCK )
?????? INNER JOIN sys.indexes AS i WITH ( NOLOCK )
?????????????? ON ddius.[object_id] = i.[object_id]
????????????????? AND i.index_id = ddius.index_id
WHERE? Objectproperty(ddius.[object_id], 'IsUserTable') = 1
?????? AND ddius.database_id = Db_id()
?????? AND user_updates > ( user_seeks + user_scans + user_lookups )
?????? AND i.index_id > 1
ORDER? BY [Difference] DESC,
????????? [Total Writes] DESC,
????????? [Total Reads] ASC;
?
--索引上的碎片
SELECT '[' + Db_name() + '].['
?????? + Object_schema_name( ddips.[object_id], Db_id())
?????? + '].['
?????? + Object_name(ddips.[object_id], Db_id())
?????? + ']'????????????????????????????????????????????????? AS [statement],
?????? i.[name]?????????????????????????????????????????????? AS [index_name],
?????? ddips.[index_type_desc],
?????? ddips.[partition_number],
?????? ddips.[alloc_unit_type_desc],
?????? ddips.[index_depth],
?????? ddips.[index_level],
?????? Cast(ddips.[avg_fragmentation_in_percent] AS SMALLINT) AS [avg_frag_%],
?????? Cast(ddips.[avg_fragment_size_in_pages] AS SMALLINT)?? AS [avg_frag_size_in_pages],
?????? ddips.[fragment_count],
?????? ddips.[page_count]
FROM?? sys.Dm_db_index_physical_stats(Db_id(), NULL, NULL, NULL, 'limited') ddips
?????? INNER JOIN sys.[indexes] i
?????????????? ON ddips.[object_id] = i.[object_id]
????????????????? AND ddips.[index_id] = i.[index_id]
WHERE? ddips.[avg_fragmentation_in_percent] > 15
?????? AND ddips.[page_count] > 500
ORDER? BY ddips.[avg_fragmentation_in_percent],
????????? Object_name(ddips.[object_id], Db_id()),
????????? i.[name]
?
日志
WRITELOG等待
這是日志等待中最常見的等待類型。在事務量很高的系統中,這種等待比較常見。當數據被修改時,在log cache和buffer cache中都會有記錄,如果在log cache中的數據在checkpoint時寫入磁盤,就會發生這種等待。但是有時候在客戶端,用戶會停止一個正在運行并且運行了很久的事務,這時會引起其回滾,這也就會導致這種等待的發生。
降低WRITELOG等待
把日志文件和數據文件及其他文件如TEMPDB存放到獨立的磁盤中。另外就是避免類似游標等的低效操作,同時加快提交事務的頻率,最后檢查I/O相關的計數器。 除此之外,刪除沒用的非聚集索引、減少日志開銷、修改索引鍵或使用填充因子減少頁分裂(第6章介紹過)、修改程序架構、把負載分攤到多個服務器或者數據庫中,這些手段都能減少出現這類等待的情況。
不要一見到這種等待就以為是I/O問題,也不要直接增加日志文件。上面已經說過,增加日志文件解決不了這類問題。 應該進行如下更加深入的分析:
查看sys.dm_io_virtual_file_stats的數據。
查看LOGBUFFER等待(下面介紹),看是否存在對日志緩沖區(log buffer)的爭搶。
查看日志文件所在磁盤的磁盤等待隊列。
查看事務的平均大小。
查看是否有大量的頁分裂,因為這樣也會導致大量的日志。
?
LOGBUFFER等待
這種等待類型相對較少出現,當一個任務正在等待存儲記錄到log buffer時,就會產生這種等待。這種等待類型的高值可能表示這日志所在的磁盤無法響應請求。
降低LOGBUFFER等待
不同的原因解決方案不同,通常包括合理存放各類文件、避免類似游標等編程技巧及加快事務提交的頻率等。
?
小結
可以查看sys.fn_vertualfilestats函數找到I/O相關的問題,并且可檢查I/O相關的計數器,比如使用SELECT * FROM fn_virtualfilestats(1,1)來查看數據庫ID為1、文件號為1的統計信息。
WRITELOG和LOGBUFFER等待的處理手段非常類似,它們的確有共同點,但是不要認為它們是相同的,需要分開對待。
?
相關SQL
--檢查活動事務的日志情況
SELECT DTST.[session_id],
?????? DES.[login_name]?????????????????????????????? AS [Login Name],
?????? Db_name(DTDT.database_id)????????????????????? AS [Database],
?????? DTDT.[database_transaction_begin_time]???????? AS [Begin Time],-- DATEDIFF(ms,DTDT.[database_transaction_begin_time], GETDATE()) AS [Durationms],
?????? CASE DTAT.transaction_type
???????? WHEN 1 THEN 'Read/write'
???????? WHEN 2 THEN 'Read-only'
???????? WHEN 3 THEN 'System'
???????? WHEN 4 THEN 'Distributed'
?????? END??????????????????????????????????????????? AS [Transaction Type],
?????? CASE DTAT.transaction_state
???????? WHEN 0 THEN 'Not fully initialized'
???????? WHEN 1 THEN 'Initialized, not started'
???????? WHEN 2 THEN 'Active'
???????? WHEN 3 THEN 'Ended'
???????? WHEN 4 THEN 'Commit initiated'
???????? WHEN 5 THEN 'Prepared, awaiting resolution'
???????? WHEN 6 THEN 'Committed'
???????? WHEN 7 THEN 'Rolling back'
???????? WHEN 8 THEN 'Rolled back'
?????? END??????????????????????????????????????????? AS [Transaction State],
?????? DTDT.[database_transaction_log_record_count]?? AS [Log Records],
?????? DTDT.[database_transaction_log_bytes_used]???? AS [Log Bytes Used],
?????? DTDT.[database_transaction_log_bytes_reserved] AS [Log Bytes RSVPd],
?????? DEST.[text]??????????????????????????????????? AS [Last Transaction Text],
?????? DEQP.[query_plan]????????????????????????????? AS [Last Query Plan]
FROM?? sys.dm_tran_database_transactions DTDT
?????? INNER JOIN sys.dm_tran_session_transactions DTST
?????????????? ON DTST.[transaction_id] = DTDT.[transaction_id]
?????? INNER JOIN sys.[dm_tran_active_transactions] DTAT
?????????????? ON DTST.[transaction_id] = DTAT.[transaction_id]
?????? INNER JOIN sys.[dm_exec_sessions] DES
?????????????? ON DES.[session_id] = DTST.[session_id]
?????? INNER JOIN sys.dm_exec_connections DEC
?????????????? ON DEC.[session_id] = DTST.[session_id]
?????? LEFT JOIN sys.dm_exec_requests DER
????????????? ON DER.[session_id] = DTST.[session_id]
?????? CROSS APPLY sys.Dm_exec_sql_text(DEC.[most_recent_sql_handle]) AS DEST
?????? OUTER APPLY sys.Dm_exec_query_plan(DER.[plan_handle]) AS DEQP
ORDER? BY DTDT.[database_transaction_log_bytes_used] DESC; -- ORDER BY [Duration ms] DESC;
?
?
?
總結
以上是生活随笔為你收集整理的收集的SQL Server性能相关资料的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Houdini湖边小屋-屋顶细分详细过程
- 下一篇: 开题报告、文献检索账号、文献综述、外文翻