服务器等待的原因
SELECT TOP 10[Wait type] = wait_type,[Wait time (s)] = wait_time_ms / 1000,[% waiting] = CONVERT(DECIMAL(12,2), wait_time_ms * 100.0 / SUM(wait_time_ms) OVER())FROM sys.dm_os_wait_statsWHERE wait_type NOT LIKE '%SLEEP%'ORDER BY wait_time_ms DESC; 读和写SELECT TOP 10 [Total Reads] = SUM(total_logical_reads) ,[Execution count] = SUM(qs.execution_count) ,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtGROUP BY DB_NAME(qt.dbid)ORDER BY [Total Reads] DESC;SELECT TOP 10 [Total Writes] = SUM(total_logical_writes) ,[Execution count] = SUM(qs.execution_count) ,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtGROUP BY DB_NAME(qt.dbid)ORDER BY [Total Writes] DESC; 数据库缺失索引SELECT DatabaseName = DB_NAME(database_id) ,[Number Indexes Missing] = count(*)FROM sys.dm_db_missing_index_detailsGROUP BY DB_NAME(database_id)ORDER BY 2 DESC;缺失索引列表信息
SELECT DatabaseName = DB_NAME(database_id),* FROM sys.dm_db_missing_index_details Order BY DB_NAME(database_id)
高开销的缺失索引
SELECT TOP 10 [Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0) , avg_user_impact , TableName = statement , [EqualityUsage] = equality_columns , [InequalityUsage] = inequality_columns , [Include Cloumns] = included_columnsFROM sys.dm_db_missing_index_groups gINNER JOIN sys.dm_db_missing_index_group_stats s ON s.group_handle = g.index_group_handleINNER JOIN sys.dm_db_missing_index_details d ON d.index_handle = g.index_handleORDER BY [Total Cost] DESC;
确定开销最高的未使用索引
SELECT TOP 10 [Total Cost]=ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0),avg_user_impact,TableName=statement, [EqualityUsage]=equality_columns,[InequalityUsage]=inequality_columns,[Include Cloumns] = included_columns FROM sys.dm_db_missing_index_groups g INNER JOIN sys.dm_db_missing_index_group_stats s ON s.group_handle = g.index_group_handle INNER JOIN sys.dm_db_missing_index_details d ON d.index_handle = g.index_handle ORDER BY [Total Cost] DESC;
确定最高开销索引所使用的脚本并显示结果。
-- Create required table structure only.-- Note: this SQL must be the same as in the Database loop given in the following step.SELECT TOP 1[Maintenance cost] = (user_updates + system_updates),[Retrieval usage] = (user_seeks + user_scans + user_lookups),DatabaseName = DB_NAME(),TableName = OBJECT_NAME(s.[object_id]),IndexName = i.nameINTO #TempMaintenanceCostFROM sys.dm_db_index_usage_stats sINNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_idWHERE s.database_id = DB_ID()AND OBJECTPROPERTY(s.[object_id], 'IsMsShipped') = 0AND (user_updates + system_updates) > 0 -- Only report on active rows.AND s.[object_id] = -999 -- Dummy value to get table structure.;-- Loop around all the databases on the server.EXEC sp_MSForEachDB 'USE [?];-- Table already exists.INSERT INTO #TempMaintenanceCostSELECT TOP 10[Maintenance cost] = (user_updates + system_updates),[Retrieval usage] = (user_seeks + user_scans + user_lookups),DatabaseName = DB_NAME(),TableName = OBJECT_NAME(s.[object_id]),IndexName = i.nameFROM sys.dm_db_index_usage_stats sINNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]AND s.index_id = i.index_idWHERE s.database_id = DB_ID()AND i.name IS NOT NULL -- Ignore HEAP indexes.AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0AND (user_updates + system_updates) > 0 -- Only report on active rows.ORDER BY [Maintenance cost] DESC;'-- Select records.SELECT TOP 10 * FROM #TempMaintenanceCostORDER BY [Maintenance cost] DESC-- Tidy up.DROP TABLE #TempMaintenanceCost 显示索引已被使用的次数,并按“使用率”排序。-- Create required table structure only.-- Note: this SQL must be the same as in the Database loop given in the -- following step.SELECT TOP 1 [Usage] = (user_seeks + user_scans + user_lookups) ,DatabaseName = DB_NAME() ,TableName = OBJECT_NAME(s.[object_id]) ,IndexName = i.nameINTO #TempUsageFROM sys.dm_db_index_usage_stats sINNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_idWHERE s.database_id = DB_ID() AND OBJECTPROPERTY(s.[object_id], 'IsMsShipped') = 0 AND (user_seeks + user_scans + user_lookups) > 0-- Only report on active rows. AND s.[object_id] = -999 -- Dummy value to get table structure.;-- Loop around all the databases on the server.EXEC sp_MSForEachDB 'USE [?];-- Table already exists.INSERT INTO #TempUsageSELECT TOP 10 [Usage] = (user_seeks + user_scans + user_lookups) ,DatabaseName = DB_NAME() ,TableName = OBJECT_NAME(s.[object_id]) ,IndexName = i.nameFROM sys.dm_db_index_usage_stats sINNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_idWHERE s.database_id = DB_ID() AND i.name IS NOT NULL -- Ignore HEAP indexes. AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 AND (user_seeks + user_scans + user_lookups) > 0 -- Only report on active rows.ORDER BY [Usage] DESC;'-- Select records.SELECT TOP 10 * FROM #TempUsage ORDER BY [Usage] DESC-- Tidy up.DROP TABLE #TempUsage
逻辑上最零碎的索引所使用的脚本
-- Create required table structure only.-- Note: this SQL must be the same as in the Database loop given in the -- following step.SELECT TOP 1 DatbaseName = DB_NAME() ,TableName = OBJECT_NAME(s.[object_id]) ,IndexName = i.name ,[Fragmentation %] = ROUND(avg_fragmentation_in_percent,2)INTO #TempFragmentationFROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) sINNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_idWHERE s.[object_id] = -999 -- Dummy value just to get table structure.;-- Loop around all the databases on the server.EXEC sp_MSForEachDB 'USE [?];-- Table already exists.INSERT INTO #TempFragmentationSELECT TOP 10 DatbaseName = DB_NAME() ,TableName = OBJECT_NAME(s.[object_id]) ,IndexName = i.name ,[Fragmentation %] = ROUND(avg_fragmentation_in_percent,2)FROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) sINNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_idWHERE s.database_id = DB_ID() AND i.name IS NOT NULL -- Ignore HEAP indexes. AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0ORDER BY [Fragmentation %] DESC;'-- Select records.SELECT TOP 10 * FROM #TempFragmentation ORDER BY [Fragmentation %] DESC-- Tidy up.DROP TABLE #TempFragmentation
获得IO高的查询
SELECT TOP 10[Average IO] = (total_logical_reads + total_logical_writes) / qs.execution_count,[Total IO] = (total_logical_reads + total_logical_writes),[Execution count] = qs.execution_count,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) ,[Parent Query] = qt.text,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtORDER BY [Average IO] DESC;
获得I/O统计
Select wait_type, waiting_tasks_count, wait_time_ms from sys.dm_os_wait_stats where wait_type like 'PAGEIOLATCH%' order by wait_type查询当前I/O锁
select DB_NAME(database_id), file_id, io_stall,io_pending_ms_ticks,scheduler_address from sys.dm_io_virtual_file_stats(NULL, NULL) t1,sys.dm_io_pending_io_requests as t2 where t1.file_handle = t2.io_handle看是那5条语句导致I/O高
select top 5 (total_logical_reads/execution_count) as avg_logical_reads,(total_logical_writes/execution_count) as avg_logical_writes,(total_physical_reads/execution_count) as avg_phys_reads,Execution_count, statement_start_offset as stmt_start_offset, sql_handle, plan_handle from sys.dm_exec_query_stats order by (total_logical_reads + total_logical_writes) Desc根据句柄得到语句
select text from sys.dm_exec_sql_text(0x03000E00D4AB884E808214016B9A00000100000000000000)
查询可以确定按 CPU 使用率衡量的、开销最高的查询
SELECT TOP 10[Average CPU used] = total_worker_time / qs.execution_count,[Total CPU used] = total_worker_time,[Execution count] = qs.execution_count,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE qs.statement_end_offset END -qs.statement_start_offset)/2),[Parent Query] = qt.text,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtORDER BY [Average CPU used] DESC; 高开销的 CLR 查询SELECT TOP 10[Average CLR Time] = total_clr_time / execution_count,[Total CLR Time] = total_clr_time,[Execution count] = qs.execution_count,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset)/2),[Parent Query] = qt.text,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats as qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtWHERE total_clr_time <> 0ORDER BY [Average CLR Time] DESC; 最常执行的查询SELECT TOP 10[Execution count] = execution_count,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset)/2),[Parent Query] = qt.text,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtORDER BY [Execution count] DESC;
受阻塞影响的查询
SELECT TOP 10[Average Time Blocked] = (total_elapsed_time - total_worker_time) / qs.execution_count,[Total Time Blocked] = total_elapsed_time - total_worker_time,[Execution count] = qs.execution_count,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset)/2),[Parent Query] = qt.text,DatabaseName = DB_NAME(qt.dbid)FROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qtORDER BY [Average Time Blocked] DESC; 最低计划重用率SELECT TOP 100[Plan usage] = cp.usecounts,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX),qt.text)) * 2 ELSE qs.statement_end_offset END -qs.statement_start_offset)/2),[Parent Query] = qt.text,DatabaseName = DB_NAME(qt.dbid),cp.cacheobjtypeFROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qtINNER JOIN sys.dm_exec_cached_plans as cp on qs.plan_handle=cp.plan_handleWHERE cp.plan_handle=qs.plan_handleORDER BY [Plan usage] ASC;数据库连接情况
SELECT session_id,connect_time,endpoint_id,auth_scheme,num_reads,num_writes,client_net_address,connection_id from sys.dm_exec_connections order by client_net_address查询优化器信息
select * from sys.dm_exec_query_optimizer_info当前执行请求
select * from sys.dm_exec_requests当前执行session
select * from sys.dm_exec_sessions 所有的调度器并产看等待运行的任务数量selectscheduler_id,current_tasks_count,runnable_tasks_countfromsys.dm_os_schedulerswherescheduler_id < 255
所有的调度器并产看等待运行的任务数量
select* fromsys.dm_os_schedulerswherescheduler_id < 255
整个CPU使用中最占用资源的查询
select top 50sum(qs.total_worker_time) as total_cpu_time,sum(qs.execution_count) as total_execution_count,count(*) as number_of_statements,qs.plan_handlefromsys.dm_exec_query_stats qsgroup by qs.plan_handleorder by sum(qs.total_worker_time) desc所有的调度器并产看等待运行的任务数量selectscheduler_id,current_tasks_count,runnable_tasks_countfromsys.dm_os_schedulerswherescheduler_id < 255
所有的调度器并产看等待运行的任务数量
select* fromsys.dm_os_schedulerswherescheduler_id < 255
整个CPU使用中最占用资源的查询
select top 50sum(qs.total_worker_time) as total_cpu_time,sum(qs.execution_count) as total_execution_count,count(*) as number_of_statements,qs.plan_handlefromsys.dm_exec_query_stats qsgroup by qs.plan_handleorder by sum(qs.total_worker_time) desc
得到在给定的时间段内花费在查询优化的时间
select * from sys.dm_exec_query_optimizer_info 重编译次数最多的25个存储过程select top 25sql_text.text,sql_handle,plan_generation_num,execution_count,dbid,objectidfromsys.dm_exec_query_stats across apply sys.dm_exec_sql_text(sql_handle) as sql_textwhereplan_generation_num >1order by plan_generation_num desc 累计使用cpu最多的查询selecthighest_cpu_queries.plan_handle,highest_cpu_queries.total_worker_time,q.dbid,q.objectid,q.number,q.encrypted,q.[text]from(select top 50qs.plan_handle,qs.total_worker_timefromsys.dm_exec_query_stats qsorder by qs.total_worker_time desc) as highest_cpu_queriescross apply sys.dm_exec_sql_text(plan_handle) as qorder by highest_cpu_queries.total_worker_time desc
清空统计项的方法
checkpoint 检查点
dbcc freeproccache 释放缓存,小心dbcc dropcleanbuffers 清空缓存,小心DBCC SQLPERF ('sys.dm_os_wait_stats', CLEAR); 清空某一项GO综合分析:
SELECT DB_ID(DB.dbid) '数据库名' , OBJECT_ID(db.objectid) '对象' , QS.creation_time '编译计划的时间' , QS.last_execution_time '上次执行计划的时间' , QS.execution_count '执行的次数' , QS.total_elapsed_time / 1000 '占用的总时间(秒)' , QS.total_physical_reads '物理读取总次数' , QS.total_worker_time / 1000 'CPU 时间总量(秒)' , QS.total_logical_writes '逻辑写入总次数' , QS.total_logical_reads N'逻辑读取总次数' , QS.total_elapsed_time / 1000 N'总花费时间(秒)' , 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 '执行语句', [Parent Query] = st.textFROM sys.dm_exec_query_stats AS QS CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) AS ST INNER JOIN ( SELECT * FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) ) DB ON QS.plan_handle = DB.plan_handlewhere 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) not like '%fetch%' ORDER BY QS.total_elapsed_time / 1000 DESC