1. 程式人生 > >The Accidental DBA:Troubleshooting Performance

The Accidental DBA:Troubleshooting Performance

顯示 tin 管理員 ant cau adding cli multi ssms

最近重新翻看The Accidental DBA,將Troubleshooting Performance部分稍作整理,方便以後查閱。
一、Baselines

網友提供的性能基線的含義:每天使用windows性能計數器定時(周期為一個月,具體需要根據自己的需求)收集服務器硬件信息,然後對硬件信息進行分析統計,計算平均值、最大值、最小值,用來與之後每天硬件信息進行比較,從而快速的估算服務器硬件狀態。

之前對基線的理解一直停留在使用Perfmon收集幾個計數器,然後拿收集到的數值和網上推薦的數值進行對比,得以判別是否異常。
數據庫服務器的基線的作用:
1、幫助你發現在它成為問題之前發生了什麽變化
2、允許你主動調整你的數據庫

3、允許你使用歷史信息解決問題
4、提供用於環境和數據趨勢的數據
5、捕獲數據,提供給管理層,以及服務器和存儲管理員,用於資源和容量規劃
基線詳細內容可參考:Capturing Baseline Data
二、Tools for On-Going Monitoring
2.1、Performance Monitor and PAL
Performance Monitor(PerfMon)提供了大量關於Windows和SQL Server的配置選項,你可以根據需要對不同的服務器進行調整,或者每次都使用相同的模板。它允許你在指定的時間段內生成一個全面的性能概要,並且你可以實時查看性能。
性能計數器的捕獲可參考PerfMon模板;性能監視器文件的分析可借助PAL工具
2.2、SQL Trace and Trace Analysis Tools
客戶端(Profiler)獲取跟蹤可參考:Trace-跟蹤高消耗的語句需添加哪些事件;服務器端跟蹤可參考:模板-Trace;導出正在運行的跟蹤模板可參考:Trace-導出已有的服務器端跟蹤
分析跟蹤文件的工具有ClearTrace和RML Utilities for SQL Server
對於SQL Server 2012及以上版本,推薦使用Extended Events代替Trace~
2.3、SQLNexus
SQLNexus用於分析SQLDiag和PSSDiag捕獲的數據。我們可以自定義SQLDiag和PSSDiag的默認模版:SQLdiag-配置文件-PerfmonCollector、SQLdiag-配置文件-ProfilerCollector、SQLdiag-配置文件-擴展
收集SQLDiag數據過於繁瑣,現在很少有人使用SQLNexus工具~
2.4、Essential DMVs for Monitoring
DMVs非常實用,每次需要使用的時候到處查找,得找個時間把這個坑填補一番

sys.dm_os_wait_stats --I want to know what SQL Server is waiting on, when there is a problem and when there isn’t.  
sys.dm_exec_requests --When I want to see what’s executing currently, this is where I start.
sys.dm_os_waiting_tasks --In addition to the overall waits, I want to know what tasks are waiting right now (and the wait_type).
sys.dm_exec_query_stats --execution count and resource usage
sys.dm_exec_query_plan --This DMV has cached plans as well as those for queries that are currently executing.
sys.dm_db_stats_properties --I always take a look at statistics in new systems, and when there’s a performance issue, initially just to check when they were last updated and the sample size.

Glenn had a great set of diagnostic queries to use for monitoring and troubleshooting.
三、Are your indexing strategies working?
對於一個全新的系統,可以按照以下三個步驟分析索引信息
step1、是否存在無效的索引
step2、是否存在臃腫和不健康的索引
step3、是否需要添加新索引
3.1、Getting rid of the dead weight
3.1.1、Fully duplicate indexes
如果不知道索引的內部機制,可能會比你想象的更難以識別重復索引。它並不總是簡單的col1列上的Index1和col1上的Index2。
在內部,SQL Server會添加列到索引,大多數命令(比如sp_helpindex)不會顯示這些內部添加的列。
可以參考Identifying Duplicate Indexes得到重復索引信息。
註意:你可能會打斷使用索引提示的應用程序,因此,請當心!通常在刪除索引之前最好先禁用一段時間。
3.1.2、Unused Indexes
從未使用的索引和重復索引一樣消耗資源。你可以使用sys.dm_db_index_usage_stats獲取索引的使用情況,註意在sqlserver2012某些版本,重建索引會清空sys.dm_db_index_usage_stats中此索引的條目
user_updates列只反映語句的數量,不反映影響的行數。例如,我執行以下語句

UPDATE Table SET ColumnX = VALUE

影響10000行,那麽表和包含ColumnX列的索引對應的user_updates都會累加1(update/delete/insert 類似)

技術分享
--數據表、索引參考Identifying Duplicate Indexes(http://www.cnblogs.com/Uest/p/6679504.html)中的測試數據
USE Test
GO
SELECT * 
INTO Test.dbo.SalesOrderDetail_IndexUsage
FROM AdventureWorks2008R2.Sales.SalesOrderDetail
GO
--CREATE UNIQUE CLUSTERED INDEX SalesOrderDetail_IndexUsage ON dbo.SalesOrderDetail(SalesOrderDetailID)
CREATE INDEX IX_SalesOrderID1 ON dbo.SalesOrderDetail_IndexUsage(SalesOrderID,rowguid,SalesOrderDetailID) INCLUDE(LineTotal)
--CREATE INDEX IX_SalesOrderID2 ON dbo.SalesOrderDetail_IndexUsage(SalesOrderID,rowguid) INCLUDE(LineTotal)
--CREATE INDEX IX_SalesOrderID3 ON dbo.SalesOrderDetail_IndexUsage(SalesOrderID,rowguid) INCLUDE(SalesOrderDetailID,LineTotal)
--CREATE UNIQUE INDEX IX_SalesOrderID4 ON dbo.SalesOrderDetail_IndexUsage(SalesOrderID,rowguid) INCLUDE(SalesOrderDetailID,LineTotal)
GO

--查看索引使用情況
select o.name,i.index_id,i.name,user_seeks,user_scans,user_lookups,user_updates
from sys.dm_db_index_usage_stats ddus
inner join sys.tables o
on ddus.object_id=o.object_id
inner join sys.indexes i
on ddus.index_id=i.index_id
and ddus.object_id=i.object_id
where database_id = db_id()
and o.name=SalesOrderDetail_IndexUsage
order by i.index_id

--查詢返回12行
select * from SalesOrderDetail_IndexUsage WHERE SalesOrderID=43659
--sys.dm_db_index_usage_stats結果
name    index_id    name    user_seeks    user_scans    user_lookups    user_updates
SalesOrderDetail_IndexUsage    0    NULL    0    0    1    0
SalesOrderDetail_IndexUsage    2    IX_SalesOrderID1    1    0    0    0

--更新影響12行
UPDATE SalesOrderDetail_IndexUsage 
SET LineTotal=LineTotal*1
WHERE SalesOrderID=43659
--sys.dm_db_index_usage_stats結果
name    index_id    name    user_seeks    user_scans    user_lookups    user_updates
SalesOrderDetail_IndexUsage    0    NULL    0    0    1    1
SalesOrderDetail_IndexUsage    2    IX_SalesOrderID1    2    0    0    1

--刪除影響12行
DELETE from SalesOrderDetail_IndexUsage 
WHERE SalesOrderID=43659
--sys.dm_db_index_usage_stats結果
name    index_id    name    user_seeks    user_scans    user_lookups    user_updates
SalesOrderDetail_IndexUsage    0    NULL    0    0    1    2
SalesOrderDetail_IndexUsage    2    IX_SalesOrderID1    3    0    0    2

--插入12行
SET IDENTITY_INSERT dbo.SalesOrderDetail_IndexUsage on
INSERT INTO SalesOrderDetail_IndexUsage
(SalesOrderID,SalesOrderDetailID,CarrierTrackingNumber,OrderQty,ProductID,SpecialOfferID,UnitPrice,UnitPriceDiscount,LineTotal,rowguid,ModifiedDate)
select * from AdventureWorks2008R2.Sales.SalesOrderDetail
WHERE SalesOrderID=43659
SET IDENTITY_INSERT dbo.SalesOrderDetail_IndexUsage OFF
--sys.dm_db_index_usage_stats結果
name    index_id    name    user_seeks    user_scans    user_lookups    user_updates
SalesOrderDetail_IndexUsage    0    NULL    0    0    1    3
SalesOrderDetail_IndexUsage    2    IX_SalesOrderID1    3    0    0    3

--註意在sqlserver2012某些版本,重建索引會清空sys.dm_db_index_usage_stats中此索引的條目
ALTER INDEX IX_SalesOrderID1 ON SalesOrderDetail_IndexUsage REBUILD

-- Clean up
--DROP TABLE Test.dbo.SalesOrderDetail_IndexUsage
View Code

3.1.3、Similar or semi-redundant indexes
你可能會有一些適合合並的索引
Indexes that have the same key (but possibly different INCLUDEd columns)

Index1: Key = LastName
Index2: Key = LastName, INCLUDE = FirstName

在這種情況下你不"需要"Index1,因為Index1能做的Index2都能做。然而Index2要寬些。因此下面的查詢需要更多的I/O

SELECT LastName,COUNT(*) FROM TableName GROUP BY LastName

但是,問題是這個查詢有多重要?這個索引使用頻率是多少?你可以使用sys.dm_db_index_usage_stats檢查索引使用情況。
Indexes that have left-based subsets of other index KEYS

Index1: Key = LastName, FirstName, MiddleInitial
Index2: Key = LastName INCLUDE = SSN
Index3: Key = LastName, FirstName INCLUDE = phone

這種情況下每個索引提供特定使用,然而你會冗余很多數據。如果我們創建一個新索引: LastName,FirstName,MiddleInitial INCLUDE(SSN,phone)
同樣,這個新索引比之前的3個索引都要寬,但是這個新索引有更多的用途而且它的總開銷更少(只需要維護一個索引,磁盤上只有一個索引,緩存中只有一個索引)。但是,你還是得確定使用窄索引的查詢有多重要,以及使用新索引會消耗多少更多的資源。
Index consolidation is a critical step in reducing waste and table bloat but there isn’t a simple answer to every consolidation option.This is another "it depends" case.
3.2、Analyze the health of your existing indexes
在清理重復/未使用/相似索引後,要確保現有的索引是健康的
Make sure your index maintenance routines at indexes on tables AND views
Make sure your index routines use a LIMITED scan if you’re only analyzing avg_fragmentation_in_percent
更多內容可查看Index Maintenance
3.3、Adding more indexes
這是一個棘手的問題。在添加索引方面有很多好/壞的做法。最糟糕的是,大多數人在沒有真正全面分析(並正確分析)現有索引的情況下添加索引。
我說正確分析索引的原因是,那些sp_helpindex和SSMS工具會隱藏部分被添加到索引的列。除非你真正了解你的索引,否則你不可能正確的添加新索引,同時合並現有索引。
雖然我強烈建議你把缺失索引作為指南,我希望你記住它們不是完美的:
The missing index DMVs only tune the plan that was executed. If the plan performed a hash join then the index is going to help the hash join. But, it’s unlikely that the join type will change. And, it might be the case that a different index would perform a different join type and the query would be even faster.
缺失索引只是針對每個索引給出最好的索引,但是你得綜合考慮,你不可能為每一個查詢單獨創建一個索引。
缺失索引可能顯示已經存在索引,SQL Server的Missing index DMV的 bug可能會使你失去理智
四、Essential PerfMon counters
可以通過導出/編輯PAL模板,得到性能計數器配置文件。日常收集使用的計數器參考:模板-Perfmon
得到性能監視器文件後,可以先在命令行使用relog命令對其處理,之後再借助PAL工具進行分析~

技術分享
--relog /?
--列出輸入文件中的性能計數器
relog F:\TroubleShooting\Perfmon\SamplePerfmonLog.blg -q -o F:\TroubleShooting\Perfmon\PerfmonCounters.txt -y
--從輸入文件中篩選出計數器
relog F:\TroubleShooting\Perfmon\DataCollector01.blg -c "\Memory\Available MBytes" -o F:\TroubleShooting\Perfmon\logfile.blg -y

--截取某段時間內的計數器到新的文件中
relog F:\TroubleShooting\Perfmon\DataCollector01.blg -b 2014/10/16 14:14:00 -e 2014/10/16 14:15:00 -o F:\TroubleShooting\Perfmon\logfile.blg -y
--轉到csv文件中
relog F:\TroubleShooting\Perfmon\DataCollector01.blg -o F:\TroubleShooting\Perfmon\Counters.csv -f csv

--以2*原采樣間隔重新收集
relog F:\TroubleShooting\Perfmon\DataCollector02.blg -b 2014/10/16 14:30:00 -e 2014/10/16 14:35:00 -o F:\TroubleShooting\Perfmon\logfile.blg -y -t 2
View Code

An important consideration when looking at performance counters, or any monitoring data from SQL Server for that matter, is that no single data point will tell you the root cause of a problem, if one occurs. For performance counters, you need to look across multiple counters for correlating information to pinpoint the root of problems.
總結
很巧原文提及的部分知識點可以從工具分類中找到,繼續搬磚 ●-●

The Accidental DBA:Troubleshooting Performance