一 从数据字典中查看大表
SELECT a.name AS 表名, MAX(b.rows) AS 记录条数 FROM sys.sysobjects AS a INNER JOIN sys.sysindexes AS b ON a.id = b.id WHERE (a.xtype = 'u') GROUP BY a.name
--当前数据库,数据文件占用与剩余空间 SELECT DB_NAME() AS DbName, name AS FileName, size/128.0 AS CurrentSizeMB, size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS INT)/128.0 AS FreeSpaceMB FROM sys.database_files;
--查看当前数据库中超过50MB的大表 Declare @SizeMB INT = 50; SELECT DB_NAME() AS DbName, s.Name AS SchemaName, t.NAME AS TableName, p.rows AS RowCounts, --SUM(a.total_pages) * 8 AS TotalSpaceKB, CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB, --SUM(a.used_pages) * 8 AS UsedSpaceKB, CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB, --(SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB, CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSpaceMB FROM sys.tables t INNER JOIN sys.indexes i ON t.OBJECT_ID = i.object_id INNER JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id LEFT OUTER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.NAME NOT LIKE 'dt%' AND t.is_ms_shipped = 0 AND i.OBJECT_ID > 255 GROUP BY t.Name, s.Name, p.Rows HAVING SUM(a.total_pages) * 8 / 1024.00>@SizeMB ORDER BY p.rows desc;
二 查看IO消耗最大的TOP 50 语句
select top 10
(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,
a.last_execution_time,
--statement_start_offset as stmt_start_offset,
--statement_end_offset as stmt_end_offset,
substring(sql_text.text, (statement_start_offset/2),
case
when (statement_end_offset -statement_start_offset)/2 <=0 then 64000
else (statement_end_offset -statement_start_offset)/2 end) as exec_statement,
sql_text.text,
db_name(sql_text.dbid) as db_name,
object_name(sql_text.objectid,sql_text.dbid) as object_name,
plan_text.query_plan
from sys.dm_exec_query_stats a
cross apply sys.dm_exec_sql_text(sql_handle) as sql_text
cross apply sys.dm_exec_query_plan(plan_handle) as plan_text
where a.last_execution_time > getdate()-1
order by
--(total_logical_reads + total_logical_writes) /Execution_count Desc
(total_logical_reads + total_physical_reads) /Execution_count Desc
三 计算signal wait占整wait时间的百分比
指令等待 CPU 资源的时间占总时间的百分比。如果超过 25% ,说明 CPU 紧张
select convert(numeric(5,4),sum(signal_wait_time_ms)*1.0/sum(wait_time_ms)) from Sys.dm_os_wait_stats
四 计算'Cxpacket'占整wait时间的百分比
Cxpacket:Sql Server 在处理一句代价很大的语句,要不就是没有合适的索引或筛选条件没能筛选足够的记录,使得语句要返回大量的结果,当 >5% 说明有问题
declare @Cxpacket bigint declare @Sumwaits bigint select @Cxpacket = wait_time_ms from Sys.dm_os_wait_stats where wait_type = 'Cxpacket' select @Sumwaits = sum(wait_time_ms) from Sys.dm_os_wait_stats select convert(numeric(5,4),@Cxpacket*1.0/@Sumwaits)
查看TOP 10 等待类型
select top 10 wait_type,convert(numeric(5,4),wait_time_ms*1.0/b.total_wait_time_ms)*100 as 'Ratio%' from sys.dm_os_wait_stats a cross join (select sum(wait_time_ms) as total_wait_time_ms from Sys.dm_os_wait_stats) b where wait_type NOT IN ( N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP', N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE', N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE', N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_WORKER_QUEUE', N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE', N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX', N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT', N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE', N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE', N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH', N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP', N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY', N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK', N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP', N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'SQLTRACE_WAIT_ENTRIES', N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT', N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'XE_DISPATCHER_JOIN', N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT') order by wait_time_ms*1.0/b.total_wait_time_ms desc
五 查询当前数据库上所有用户表格在Row lock上发生阻塞的频率
declare @dbid int select @dbid = db_id() Select dbid=database_id, objectname=object_name(s.object_id) , indexname=i.name, i.index_id --, partition_number , row_lock_count, row_lock_wait_count , [block %]=cast (100.0 * row_lock_wait_count / (1 + row_lock_count) as numeric(15,2)) , row_lock_wait_in_ms , [avg row lock waits in ms]=cast (1.0 * row_lock_wait_in_ms / (1 + row_lock_wait_count) as numeric(15,2)) from sys.dm_db_index_operational_stats (@dbid, NULL, NULL, NULL) s, sys.indexes i where objectproperty(s.object_id,'IsUserTable') = 1 and i.object_id = s.object_id and i.index_id = s.index_id order by row_lock_wait_count desc
六 检查索引的使用情况
select db_name(database_id) as N'数据库名称', object_name(a.object_id) as N'表名', b.name N'索引名称', user_seeks N'用户索引查找次数', user_scans N'用户索引扫描次数', last_user_seek N'最后查找时间', last_user_scan N'最后扫描时间', rows as N'表中的行数' from sys.dm_db_index_usage_stats a join sys.indexes b on a.index_id = b.index_id and a.object_id = b.object_id join sysindexes c on c.id = b.object_id where database_id=db_id('WMSDB_FG') --指定数据库 and object_name(a.object_id) not like 'sys%' --and object_name(a.object_id) like '表名' --指定索引表 -- and b.name like '索引名' --指定索引名称 可以先使用 sp_help '你的表名' 查看表的结构和所有的索引信息 order by user_seeks,user_scans,object_name(a.object_id)
七 检查缓冲区的命中率
SELECT (a.cntr_value * 1.0 / b.cntr_value) * 100.0 [BufferCacheHitRatio] FROM (SELECT * FROM sys.dm_os_performance_counters WHERE counter_name = 'Buffer cache hit ratio' AND object_name = CASE WHEN @@SERVICENAME = 'MSSQLSERVER' THEN 'SQLServer:Buffer Manager' ELSE 'MSSQL$' + rtrim(@@SERVICENAME) + ':Buffer Manager' END ) a CROSS JOIN (SELECT * from sys.dm_os_performance_counters WHERE counter_name = 'Buffer cache hit ratio base' and object_name = CASE WHEN @@SERVICENAME = 'MSSQLSERVER' THEN 'SQLServer:Buffer Manager' ELSE 'MSSQL$' + rtrim(@@SERVICENAME) + ':Buffer Manager' END ) b;
八 查看数据库从上次启动以来所发生的死锁的次数
SELECT instance_name,cntr_value AS NumOfDeadLocks FROM sys.dm_os_performance_counters WHERE object_name = 'SQLServer:Locks' AND counter_name = 'Number of Deadlocks/sec' AND instance_name = '_Total'
九 获取一段时间内累计的File reads
--1.先执行下面的语句 SELECT DB_NAME(mf.database_id) AS databaseName , mf.physical_name , divfs.num_of_reads , --other columns removed in this section. See Listing 6.14 for complete code GETDATE() AS baselineDate INTO #baseline FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS divfs JOIN sys.master_files AS mf ON mf.database_id = divfs.database_id AND mf.file_id = divfs.file_id; --2.过一段时间后执行下面的SQL WITH currentLine AS ( SELECT DB_NAME(mf.database_id) AS databaseName , mf.physical_name , num_of_reads , --other columms removed GETDATE() AS currentlineDate FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS divfs JOIN sys.master_files AS mf ON mf.database_id = divfs.database_id AND mf.file_id = divfs.file_id ) SELECT currentLine.databaseName , currentLine.physical_name , --gets the time difference in milliseconds since the baseline was taken DATEDIFF(millisecond,baseLineDate,currentLineDate) AS elapsed_ms, --gets the change in time since the baseline was taken currentLine.num_of_reads - #baseline.num_of_reads AS num_of_reads --other columns removed FROM currentLine INNER JOIN #baseline ON #baseLine.databaseName = currentLine.databaseName AND #baseLine.physical_name = currentLine.physical_name
十. 如何监控TempDB的IO瓶颈
1. 三个windows 性能计数器
-- 每次数据传输的平均时间 a) AVG.Disk sec/Transfer--磁盘读数据所需的平均时间 b) AVG.Disk sec/Read--磁盘写数据所需的平均时间 c)AVG.Disk sec/Write
2.DMV视图
下面使用sys.dm_io_virtual_file_stats来确认IO瓶颈,它返回数据文件和日志文件的 I/O 统计信息,包括对文件发出的读取/写入次数以及总字节数, file_id字段中1 是数据文件,2是日志文件,脚本如下:
SELECT DB_NAME(database_id) AS 'DBName',
file_id,
io_stall_read_ms/num_of_reads AS 'Avg Read ms/Transfer',
io_stall_write_ms/num_of_writes AS 'Avg Write ms/Transfer'
FROM sys.dm_io_virtual_file_stats(NULL,null) a
WHERE database_id = 2
下面是数据文件及日志文件性能指标建议列表,仅供参考
数据文件 | 日志文件 |
目标:<10ms | 目标:<5ms |
可接受:10 ~ 20 ms | 可接受:5~15ms |
不可接受:>20ms | 不可接受:>15ms |
3.查看tempdb空间使用情况
user_object_reserved_page_count 用户对象包括: 临时表,表变量,表值函数中返回的表,定义的表和索引
internal_object_reserved_page_count 内部对象包括:排序段,哈希联接,游标
version_store_reserved_page_count 行版本包括: 触发器,运行联机索引,快照隔离级别或使用行版本控制
unallocated_extent_page_count:未分配空间(可用空间)
select 'Tempdb' as DB, GETDATE() as [Time], SUM(user_object_reserved_page_count)*8.0/1024 as '用户对象占用总空间_M', SUM(internal_object_reserved_page_count)*8.0/1024 as '内部对象占用总空间_M', SUM(version_store_reserved_page_count) * 8.0/1024 as '行版本占用总空间_M', SUM(unallocated_extent_page_count) *8.0/1024 as '未分配总空间_M' from sys.dm_db_file_space_usage where database_id=2
十一 使用性能计数器检测SQL SERVER服务器是否存在IO瓶颈
可以使用性能计数器来检查I/O子系统的负荷。下面的计数器可用于检查磁盘性能:
PhysicalDisk Object:Avg.DiskQueue Length
:计算从物理磁盘中的平均读和写的请求队列。过高的值代表磁盘操作处于等待状态。当这个值在SQLServer峰值时长期超过2,证明需要注意了。如果有多个硬盘,就需要把这些数值除以2。比如,有4个硬盘,且队列为10,那么平均值就是10/4=2.5,虽然也证明需要关注,但不能使用10这个值。
Avg.Disk Sec/Read
和Avg.Disk Sec/Write
:显示从磁盘读或者写入磁盘的平均时间。10ms内是很好的表现,20以下还算能接受。高于此值证明存在问题。
Physical Disk:%Disk Time
:在磁盘忙于读或者写请求的时候持续时间的比率。根据拇指定律,此值应该小于50%。
Disk Reads/Sec
和Disk Writes/Sec
计数器显示出在磁盘中读写操作的速率。这两个值应该小于磁盘能力的85%。当超过此值,磁盘的访问时间将以指数方式增长。
可以通过以下方式来计算逐渐增长的负载的能力。一种方法是使用SQLIO。你应该找到吞吐量比较稳定,但缓慢增长。
可以使用以下公式来计算RAID配置:
Raid 0: I/O per disk = (reads + writes) / number ofdisks
Raid 1: I/O per disk = [reads + (writes*2)] / 2
Raid 5: I/O per disk = [reads + (writes*4)] / number of disks
Raid 10: I/O per disk = [reads + (writes*2)] / number of disks
比如:对于RAID 1,如果得到下面的计数器:
Disk Reads/sec = 90
Disk Writes/sec =75
- 1
- 2
根据公式:[reads + (writes*2)] / 2 or [90 + (75*2)] / 2 = 120I/OS
每个磁盘。