Hacer amigos de SQL Server y PerfMon

En la foto hay una escena de la vieja comedia "Airplane": los boomers lo recuerdan.



Ella no está aquí por casualidad. Pero útil después.

A dba no le gusta perfmon


No es en absoluto porque la interfaz PerfMon no ha cambiado con Windows NT 3.1 (?) Y devuelve el calor de dos milésimas. Por cierto, tal vez alguien sepa la explicación de este hecho extraño. El panel de control se reescribe varias veces al año. Incluso la calculadora fue reescrita. Pero no perfMon.

DBA piensa con palabras de tapa. Cuando un buen médico de DBA llega a un servidor SQL enfermo, abre su maletín, y en el maletín hay una gran cantidad de cuartos que le sirven fielmente. Él toma el más corto de ellos de memoria. A veces, un DBA puede analizar las métricas de PerfMon: disco físico o longitud de la cola de disco. Sin embargo, un DBA real obtendrá sus propias métricas del servidor SQL, no a través de PerfMon, sino con un parche, por ejemplo, como este:

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

Cuando los representantes de TI, divorciados de la esfera de DBA, le preguntan, "¿qué métricas quieres que recopilemos?" (bueno, hay todo tipo de splunk, cuadrado, etc.), luego el DBA comienza a pensar en los scripts y el resto en las métricas de perfmon. Al mismo tiempo, como regla, intentan volcar todas las métricas en el DBA. Cuando esto sucede, la imagen es inútil en su congestión. Y luego un video corto de la película "Avión" me ayudará .

Como resultado, DBA escribe keri, que escribe estadísticas cada N minutos en alguna placa de la base de datos DBAtasks. ¿Te reconoces a ti mismo?

Abogado Diablo (perfmon)


Sin embargo, los contadores de perfmon son una herramienta estándar. Se pueden registrar, establecer alertas, pero lo más importante es que hay una gran cantidad de sistemas que "fusionan" estas métricas de muchas máquinas en un repositorio centralizado, le permiten analizarlas y crear gráficos hermosos (y no como perfmon).

¡Resulta que podemos hacer amigos con el mundo SQL y el mundo PerfMon!

A continuación les mostraré cómo.

Ahora los detalles irán


Como ejemplo, mostraremos cómo exportar métricas que el SQL mismo no publica en PerfMon. Por ejemplo, la consulta a continuación:

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;

devuelve la cantidad de espacio tempdb utilizado por el almacén de versiones (para la instantánea), los objetos de usuario (#tab y ## pestaña) y el espacio de almacenamiento ordenado / temporal. Creemos métricas para ellos (mayores de 18 años, los equipos no están documentados)

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')

Esto creará tres métricas en SQLServer -> UserSettable -> Query. Las métricas son enteros: int (no bigint). Además, su significado se interpreta como es. Es decir, si necesita un delta del valor anterior, entonces esta es su preocupación. Pero en este caso, solo necesitamos asignar valores a las métricas:

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)

En realidad, eso es todo. Ahora solo llame a este código regularmente y todo funcionará.

Contadores Delta


Ahora hagamos un contador delta. Este será el tiempo de espera de bloqueo en ms.

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

Aquí puede objetarme que tal métrica ya existe:

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

Pero esta métrica solo es eventualmente consistente. Como recordarán, si los protones son inestables, cualquier base de datos en el universo es eventualmente consistente. Es decir, si crea un bloqueo y observa el valor de esta métrica, ¡entonces no crecerá! Y solo al final del bloqueo, su valor saltará bruscamente durante todo el tiempo de espera. En el gráfico, en lugar de la 'meseta' esperada, obtendrá un pico agudo, que también estropea su escala a lo largo del eje Y.

El mismo problema es con kvery:

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

Por lo tanto, debemos agregar el tiempo de los actuales al tiempo de los bloqueos 'completados':

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

Esta consulta ya da la meseta correcta en el gráfico.

Ahora debemos considerar el delta del valor anterior. Hay dos maneras:

  • Diseñe un proceso como un trabajo que se llama con frecuencia (por ejemplo, una vez por minuto). Cree una etiqueta para almacenar valores anteriores. De hecho, a menudo es malo llamar al trabajo (gastos generales + competencia por el historial de ejecución de los trabajos), y puede prescindir de una placa adicional:
  • Cree un proceso que se ejecute en un bucle sin fin con waitfor. El proceso recuerda el valor anterior en la variable. Procesaremos el proceso como un trabajo con dos horarios: al inicio y una vez por hora (en caso de que el trabajo caiga, entonces se reiniciará)

En el segundo caso, es bastante posible hacer un ciclo cada cinco segundos o incluso con más frecuencia. Entonces, obtenemos:

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

Tenga en cuenta que la primera vez que ejecute un bucle DBCC, se omitirá (lo cual es correcto), ya que @OLDlock (y bloquear) será nulo.

All Articles