一 从数据字典中查看大表

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/ReadAvg.Disk Sec/Write:显示从磁盘读或者写入磁盘的平均时间。10ms内是很好的表现,20以下还算能接受。高于此值证明存在问题。

Physical Disk:%Disk Time:在磁盘忙于读或者写请求的时候持续时间的比率。根据拇指定律,此值应该小于50%

Disk Reads/SecDisk 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每个磁盘。