SQLServer诊断数据库性能(摘自网络)
一般而言,在诊断数据库性能问题的时候,我们会在早期做一些快速的分析,例如查看等待信息,这里,会通过sys.dm_os_wait_stats这个DMV来快速的一窥情况,通过这个DMV来查看数据库中有哪些资源处于等待,因为很多的时候,数据库的性能变差,问题就出现在等待上面。分析等待,是个不错的切入点。可以让我们开始“顺藤摸瓜” 下面就举个例子,例如,如果发现PAGEIOLATCH_SH这个等待很多,那么可能就说明很多的回话都在获取缓存页的时候有延迟了。这个情况的发生,可以是因为有很多的回话,或者某一个回话请求可过多的数据页,但是此时这些需要的数据页并没有加载在数据缓冲区中。SQL Server要为每一个数据页去分配缓冲页,同时,也会在数据页上面放置一个锁。这里可能的瓶颈问题就是磁盘I/O。可能是磁盘子系统无法快速的返回数据页来响应这个多会话对,导致了这个等待的产生。 到这里,可能有人就认为:是不是磁盘子系统太慢了,要去购买更好的磁盘。 注意:分析到这里为止,这是说明:存在磁盘I/O问题,是因为磁盘子系统响应过慢,但是不说明磁盘子系统不满足现在的I/O。 那么这个时候,我们要进一步的分析,此时,因为我们随着I/O这条线往下面走,确认:到底是不是I/O产生了问题。 此时,我们可以进一步的查看sys.dm_io_virtual_file_stats,来证明是不是因为文件的读写问题产生了性能问题。我们也可以通过这个DMV来查看数据库中的每个文件的I/O的读写情况。 另外,作为补充的和确认的步骤,也要查看Physical DiskAvg. Disk Reads/sec,Physical DiskAvg. Disk Writes/sec性能计数器。】 如果这些值都很高,那么,我们基本可以估计:是I/O问题了。 确定了基本的问题的方向之后,那么我们就进一步的看看,这个问题产生的“罪魁祸首”。 此时,我们可以查看sys.dm_exec_query_stats来查看计划缓存,主要查看那最多物理读取的计划,然后查看这个计划对应的查询语句,看看这个查询是否因为“缺失索引”产生的问题。 1、不要数据库文件,例如日志,数据文件放在系统盘中。 2、日志,数据文件要分开,最好将系统的数据库与我们的数据库分开放在不同的磁盘中 3、建议将tempdb放在单独的磁盘。因为日志文件是按顺序写的,而数据文件是随机读写的,所以,放 ? ?在一起,势必使得磁盘的磁头来回的寻道。 4、在选择磁盘的时候,不要一味的考虑容量,而不考虑吞度量,例如要购买一个1TB的磁盘,最好是 ? ?买几个小的磁盘,例如300GB的,将之拼接为1TB。主要是为了使得磁盘读取数据的并行度加大 另外,还需要注意数据库内部的一些信息: 1.数据页每个大小事8K,而数据库在分配的时候,每次不是按照页来分配的,而是按照块,即,每次分配64K的空间,也就是8个页,那么我们在为每一个磁盘分区分卷的时候,最好将之定位64K,毕竟磁盘过多的分页,这个道理和毕竟过多的数据库分页一样的。 2. 要检查磁盘的扇区是否对齐,这个问题发生在win2003以及之前的版本,win2008不用管了。 关于磁盘扇区对齐,这个问题搞定之后,可以将磁盘的I/O行提升20%~30%。 可以采用diskpart命令来搞定。方法如下(注意,在磁盘扇区对齐的时候,要将分区里面的文件备份到其他地方): 1.“开始”->"运行",输入“diskpart” 2、输入“list disk”,这里将会列出所有的磁盘,注意:是物理的磁盘,如果是采用的阵列,那么这就会列出所有的磁盘。 3、select disk XXX”,其中XXX就是磁盘的编号,例如0,1,2等 4、然后查询这个磁盘的分区,运行“list partition”,将分区全部列出来 5、对齐扇区,运行“create partition primary algin=64” 不管数据库大小,一般是设置成按多少MB增长,而不是百分比. 适当时候,可以关闭数据库自动自动增长,手动设置数据库增长大小,自动增长不合适会产生磁盘碎片 如何查看等待的问题,因为有很多的等待是系统的等待,不是我们要研究,下面的脚本非常实用: SELECT TOP 10 wait_type, max_wait_time_ms wait_time_ms,'microsoft yahei';">signal_wait_time_ms,'microsoft yahei';">wait_time_ms - signal_wait_time_ms AS resource_wait_time_ms,'microsoft yahei';">100.0 * wait_time_ms / SUM(wait_time_ms) OVER ( ) AS percent_total_waits,'microsoft yahei';">100.0 * signal_wait_time_ms / SUM(signal_wait_time_ms) OVER ( ) AS percent_total_signal_waits,'microsoft yahei';">100.0 * ( wait_time_ms - signal_wait_time_ms ) / SUM(wait_time_ms) OVER ( ) AS percent_total_resource_waits FROM sys.dm_os_wait_stats WHERE wait_time_ms > 0 -- 移除为0的wait_time AND wait_type NOT IN -- 将不相关的等待移除 ( 'SLEEP_TASK','BROKER_TASK_STOP','BROKER_TO_FLUSH','microsoft yahei';">'SQLTRACE_BUFFER_FLUSH','CLR_AUTO_EVENT','CLR_MANUAL_EVENT','microsoft yahei';">'LAZYWRITER_SLEEP','SLEEP_SYSTEMTASK','SLEEP_BPOOL_FLUSH','microsoft yahei';">'BROKER_EVENTHANDLER','XE_DISPATCHER_WAIT','FT_IFTSHC_MUTEX','microsoft yahei';">'CHECKPOINT_QUEUE','FT_IFTS_SCHEDULER_IDLE_WAIT','microsoft yahei';">'BROKER_TRANSMITTER','KSOURCE_WAKEUP','LOGMGR_QUEUE','ONDEMAND_TASK_QUEUE','microsoft yahei';">'REQUEST_FOR_DEADLOCK_SEARCH','XE_TIMER_EVENT','BAD_PAGE_PROCESS','microsoft yahei';">'DBMIRROR_EVENTS_QUEUE','BROKER_RECEIVE_WAITFOR','microsoft yahei';">'PREEMPTIVE_OS_GETPROCADDRESS','PREEMPTIVE_OS_AUTHENTICATIONOPS','microsoft yahei';">'WAITFOR','DISPATCHER_QUEUE_SEMAPHORE','XE_DISPATCHER_JOIN','microsoft yahei';">'RESOURCE_QUEUE' ) ORDER BY wait_time_ms DESC 磁盘整列 RAID02块磁盘就可以,读写性能佳,使用率100%,不容错 RAID12块磁盘就可以,读写性能一般,使用率50%,容错(存放单个的日志文件,日志文件的按顺序读写) RAID53块磁盘就可以,读性能佳,写一般(10:1),使用率 磁盘容量为(N-1)*磁盘容量,容错 RAID104块磁盘就可以,读写性能佳,使用率50%,不容错 --查询每一个数据库占用的内存 SET TRAN ISOLATION LEVEL READ UNCOMMITTED SELECT ISNULL(DB_NAME(database_id),'ResourceDb') AS DatabaseName ,CAST(COUNT(row_count) * 8.0 / (1024.0) AS DECIMAL(28,2)) AS [Size (MB)] FROM sys.dm_os_buffer_descriptors GROUP BY database_id ORDER BY DatabaseName --查询表或者索引占用的内存 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED OBJECT_NAME(p.[object_id]) AS [TableName]
FROM sys.allocation_units AS a INNER JOIN sys.dm_os_buffer_descriptors AS b ON a.allocation_unit_id = b.allocation_unit_id INNER JOIN sys.partitions AS p INNER JOIN sys.indexes i ON p.index_id = i.index_id AND p.[object_id] = i.[object_id] ON a.container_id = p.hobt_id WHERE b.database_id = DB_ID() AND p.[object_id] > 100 GROUP BY p.[object_id],i.name ORDER BY NumberOf8KPages DESC --性能监视器--计数器 SQL Server:Buffer ManagerBuffer Cache Hit Ratio SQL Server:Buffer ManagerPage Life Expectancy SQL Server:Buffer ManagerFree Pages SQL Server:Buffer ManagerFree List Stalls/sec SQL Server:Buffer ManagerLazy Writes/sec SQL Server:Memory ManagerTarget Server Memory (KB) SQL Server:Memory ManagerTotal Server Memory (KB) SQL Server:Memory ManagerMemory Grants Outstanding SQL Server:Memory ManagerMemory Grants Pending 在上面的计数器中,纠正一个传言:Page Life Expectancy一般不要超过300. 300这个值是微软在很多年前的文档中给出的,现在的很多的书籍和资料,也是这样写的。但是这是不对的。因为在很多年之前,也就是sql server2000的时代,4G的物理内存就认为是非常的大了,而且sql server可用的数据缓冲池最大也只有1.6GB。但是,现在,服务器以及数据库的可用的内存已经发生了很大的变换,SQL Server使用非常多的内存。所以这个数据300也要发生变换,现在这个值计算公式为:(服务器的物理内存总数/4)*300,如果一个32GB的服务器,那么这个值就是2400 关于DMV呢,基本都是见名知意的: sys.dm_exec_query_memory_grants:可以用来找出哪些查询在等待着分配内存。 sys.dm_os_memory_cache_counters:给出现在使用内存的一个快照。 sys.dm_os_sys_memory:给出了现在操作系统使用内存的情况 sys.dm_os_memory_clerks:给出了与SQL Server中每个组件使用的内存的情况。 下面我们来看看“内存分页”的问题以及解决办法。 自从SQL Server 2005 SP2开始,SQL Server就会发生工作区裁剪的问题,就是说:SQL Server使用的内存在操作系统发出了内存紧急命令之后,SQL Server占用的会被一下子收回去一部分。不用说,这对SQL Server性能影响是非常的大的。 同时,也会在Window Log中也会记录“a significant part of SQL Server process memory has been paged out”。 我们可以查看得出这个问题。 发生这个问题的原因主要如下: 1. 不正确的设置:max server memory 这个选项。 2. Lock Pages in Memory没有被使用。 3.大量的操作系统缓存被用来非缓冲的I/O操作,例如,在操作系统上面copy文件之类的。 4.硬件驱动问题。 解决这个问题最快的办法就是:强制SQL Server锁住它使用的内存,这通过设置Lock Pages in Memory为true来搞定。 索引碎片,主要就是在有索引的表上面不断的进行数据操作(增,删,改) 从而导致索引页上面出现很多的碎片空间,这一点和我们磁盘的碎片产生的道理类似, 索引碎片 找起来也简单,我也收集了一些查询,可以很快的找出碎片问题: 开始重建碎片率大于80%的索引,语句如下: ALTER INDEX IX_gdid ON t_product REBUILD DB_NAME() AS DatbaseName
INTO #TempFragmentation FROM sys.dm_db_index_physical_stats(db_id(),null,null) s INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id INNER JOIN sys.objects o ON i.object_id = O.object_id WHERE 1=2 EXEC sp_MSForEachDB 'USE [?]; INSERT INTO #TempFragmentation SELECT TOP 20 WHERE s.database_id = DB_ID() AND i.name IS NOT NULL AND OBJECTPROPERTY(s.[object_id],''IsMsShipped'') = 0 ORDER BY [Fragmentation %] DESC' SELECT top 20 * FROM #TempFragmentation ORDER BY [Fragmentation %] DESC DROP TABLE #TempFragmentation 有些可以Fragmentation 超过30%就rebuild 了,利用sys.dm_db_index_physical_stats SELECT object_name(ps.OBJECT_ID) table_name,b.name index_name,ps.avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats (DB_ID(),NULL,NULL) AS ps INNER JOIN sys.indexes AS b ON ps.OBJECT_ID = b.OBJECT_ID AND ps.index_id = b.index_id WHERE ps.database_id = DB_ID() ? ? and avg_fragmentation_in_percent>30 ? ? and name is not null ORDER BY avg_fragmentation_in_percent desc --这个语句去查询哪些sql的逻辑读很高,之后进行优化 SELECT SS.SUM_EXECUTION_COUNT,'microsoft yahei';"> ? ? ? ? ? ? ? ?T.TEXT,'microsoft yahei';"> ? ? ? ? ? ? ? ?SS.SUM_TOTAL_ELAPSED_TIME,'microsoft yahei';"> ? ? ? ? ? ? ? ?SS.SUM_TOTAL_WORKER_TIME,'microsoft yahei';"> ? ? ? ? ? ? ? ?SS.SUM_TOTAL_LOGICAL_READS,'microsoft yahei';"> ? ? ? ? ? ? ? ?SS.SUM_TOTAL_LOGICAL_WRITES FROM (SELECT S.PLAN_HANDLE,'microsoft yahei';"> ? ? ? ? ? ? ? ? ? ? ? ? SUM(S.EXECUTION_COUNT) SUM_EXECUTION_COUNT,'microsoft yahei';"> ? ? ? ? ? ? ? ? ? ? ? ? SUM(S.TOTAL_ELAPSED_TIME) SUM_TOTAL_ELAPSED_TIME,'microsoft yahei';"> ? ? ? ? ? ? ? ? ? ? ? ? SUM(S.TOTAL_WORKER_TIME) SUM_TOTAL_WORKER_TIME,'microsoft yahei';"> ? ? ? ? ? ? ? ? ? ? ? ? SUM(S.TOTAL_LOGICAL_READS) SUM_TOTAL_LOGICAL_READS,'microsoft yahei';"> ? ? ? ? ? ? ? ? ? ? ? ? SUM(S.TOTAL_LOGICAL_WRITES) SUM_TOTAL_LOGICAL_WRITES ? ? ? ? ?FROM SYS.DM_EXEC_QUERY_STATS S ? ? ? ? ?GROUP BY S.PLAN_HANDLE ? ? ? ? ?) AS SS ? ? ? ? ?CROSS APPLY SYS.DM_EXEC_SQL_TEXT(SS.PLAN_HANDLE) T ORDER BY SUM_TOTAL_LOGICAL_READS DESC (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |