结交SQL Server和PerfMon朋友

照片中有一个很好的古老喜剧《飞机》中的场景-婴儿潮一代记得它。



她不是来这里的。但是以后有用。

dba不喜欢perfmon


根本不是因为PerfMon界面在Windows NT 3.1(?)中没有更改,并且可以回馈千分之二的温暖。顺便说一句,也许有人知道这个奇怪事实的解释。一年重写控制面板几次。甚至计算器也被改写。但不是perfMon。

DBA用掩饰词思考。当一名优秀的DBA医生到达一台有问题的SQL服务器时,他打开了手提箱,手提箱中有大量的宿舍可以为他提供忠实的服务。他从记忆中拿走了最短的东西。有时,DBA可以查看PerfMon的指标-物理磁盘或磁盘队列长度。但是,真正的DBA不会通过PerfMon来获取自己的SQL Server度量标准,而是使用例如以下补丁程序:

select * from sys.dm_os_performance_counters 
  where object_name='SQLServer:Buffer Manager' 
    and counter_name like 'Page life expectancy%' 
	and instance_name=''

当IT代表从DBA领域离婚时,问他:“您希望我们收集什么指标?” (嗯,有各种各样的杂乱无章的内容,等等),然后DBA开始考虑脚本,其余的考虑性能指标。同时,通常,他们尝试将所有指标转储到DBA上。发生这种情况时,图片将变得毫无用处。然后电影“飞机”中的一段短片将对我有所帮助

结果,DBA编写了keri,它每隔N分钟将统计信息写入DBAtasks数据库中的某个板块。你认识你自己吗?

提倡恶魔(perfmon)


不过,性能计数器是一种标准工​​具。可以记录它们,设置警报,但是最重要的是,有许多系统将这些指标从许多计算机“合并”到一个集中的存储库中,使您可以分析它们并构建漂亮的(而不是像perfmon一样)的图表。

事实证明,我们可以与SQL世界和PerfMon世界成为朋友!

下面我将展示如何。

现在细节将


作为示例,我们将展示如何将SQL本身未发布的指标导出到PerfMon。例如,下面的查询:

select
  convert(numeric(10,2),round(((sum(version_store_reserved_page_count)*1.0)/128.00),2)),
  convert(numeric(10,2),round(((sum(user_object_reserved_page_count)*1.0)/128.00),2)),
  convert(numeric(10,2),round(((sum(internal_object_reserved_page_count)*1.0)/128.00),2))
from
  tempdb.sys.dm_db_file_space_usage;

返回版本存储(用于快照),用户对象(#tab和##选项卡)和排序/临时存储空间使用的tempdb空间量。让我们为他们创建指标(超过18个团队,没有文档记录)

dbcc addinstance ('SQLServer:User Settable', 'TempDB version store KB')
dbcc addinstance ('SQLServer:User Settable', 'TempDB user store KB')
dbcc addinstance ('SQLServer:User Settable', 'TempDB sort store KB')

这将在SQLServer-> UserSettable-> Query中创建三个指标。指标是整数-int(不是bigint)。另外,它们的含义按原样解释。也就是说,如果您需要与先前值相差一个增量,那么这就是您的关注点。但是在这种情况下,我们只需要为指标分配值即可:

declare @TEMPDBver int, @TEMPDBuser int, @TEMPDBsort int
select

@TEMPDBver = convert(numeric(10,2),round(((sum(version_store_reserved_page_count) *1.0)/128.00),2)),
@TEMPDBuser = convert(numeric(10,2),round(((sum(user_object_reserved_page_count) *1.0)/128.00),2)),
@TEMPDBsort = convert(numeric(10,2),round(((sum(internal_object_reserved_page_count) *1.0)/128.00),2))
from tempdb.sys.dm_db_file_space_usage;

if @TEMPDBver is not null    
  dbcc setinstance ('SQLServer:User Settable', 'Query', 
    'TempDB version store KB', @TEMPDBver)
if @TEMPDBuser is not null   
  dbcc setinstance ('SQLServer:User Settable', 'Query', 
   'TempDB user store KB', @TEMPDBuser)
if @TEMPDBsort is not null   
  dbcc setinstance ('SQLServer:User Settable', 'Query', 
    'TempDB sort store KB', @TEMPDBsort)

实际上,仅此而已。现在,只需定期调用此代码,一切都会正常。

三角洲柜台


现在让我们做一个增量计数器。这将是锁定超时(以毫秒为单位)。

dbcc addinstance ('SQLServer:User Settable', 'LOCK ms per s')

在这里,您可以反对我这样的指标已经存在:

select * from sys.dm_os_performance_counters 
  where counter_name like 'Lock Wait Time (ms)%' 
    and instance_name='_Total'
    and object_name='SQLServer:Locks'

但是这个指标最终还是一致的。您还记得,如果质子不稳定,那么宇宙中的任何数据库最终都是一致的。也就是说,如果创建一个锁并查看该指标的值,则它将不会增长!而且只有在锁定结束时,它的值才会在整个等待时间内急剧上升。在图表上,而不是预期的“平稳”的,你会得到一个尖峰,这也败坏你的规模沿Y轴,

同样的问题是kvery:

select sum(wait_time_ms) 
  from sys.dm_os_wait_stats 
  where wait_type like 'LCK_%'

因此,我们必须将当前时间添加到“完成”锁的时间中:

declare @NEWlock bigint
select @NEWlock=sum(wait_time_ms) 
  from sys.dm_os_wait_stats 
  where wait_type like 'LCK_%' -- finished waits
select @NEWlock=@NEWlock+isnull(sum(waittime),0) 
  from master.dbo.sysprocesses 
  where blocked>0 and lastwaittype like 'LCK_%' -- waits in progress

该查询已经在图表上提供了正确的平稳期。

现在我们需要考虑先前值的增量。有两种方法:

  • 将流程设计为经常被调用的工作(例如,每分钟一次)。创建一个标签来存储以前的值。实际上,打电话给Job通常很不好(开销+ Jobs的执行历史的竞争),您可以不用额外的盘子来做:
  • 创建一个使用waitfor无限循环运行的进程。该过程会记住变量中的先前值。我们将按照以下两个时间表将流程作为作业进行处理:在启动时和每小时进行一次(以防工作失败,然后它将重新启动)

在第二种情况下,很有可能每五秒钟或更频繁地执行一个循环。因此,我们得到:

declare @OLDlock bigint, @NEWlock bigint
declare @lock int, @seconds int = 5 -- must match WAITFOR
loop:
  set @OLDlock=@NEWlock -- shift new to old
  select @NEWlock=sum(wait_time_ms) 
    from sys.dm_os_wait_stats 
	where wait_type like 'LCK_%' -- finished waits
  select @NEWlock=@NEWlock+isnull(sum(waittime),0) 
    from master.dbo.sysprocesses 
	where blocked>0 and lastwaittype like 'LCK_%' -- waits in progress
  set @lock=(@NEWlock-@OLDlock)/@seconds -- this is delta
  if @lock is not null    
    dbcc setinstance ('SQLServer:User Settable', 'Query', 
	  'LOCK ms per s', @lock)
  waitfor delay '00:00:05' 
goto loop

请注意,由于@OLDlock(和),第一次运行DBCC循环将被跳过(正确)。 )为空。

All Articles