Uma necessidade bem comum no dia a dia de um administrador de banco de dados é analisar o uso de CPU da instância. Por este motivo, compartilharei nesse artigo, uma consulta Transact-SQL (T-SQL) para obter essa informação de um banco SQL Server 2008+ ou Azure SQL Database.
Embora seja possível obter o uso de CPU utilizando ferramentas gráficas, muitas vezes é interessante conseguir ter acesso a essa informação utilizando uma query, pois você pode armazenar esse histórico numa tabela, gerar alertas e ações personalizadas conforme o valor obtido, criar gráficos no Power BI, etc…
Como retornar o uso de CPU utilizando T-SQL
Para retornar o uso de CPU do servidor utilizando T-SQL, utilize o script abaixo:
DECLARE @ts_now BIGINT = (
SELECT
cpu_ticks / ( cpu_ticks / ms_ticks )
FROM
sys.dm_os_sys_info
);
SELECT
SQLProcessUtilization AS [SQL Server Process CPU Utilization],
SystemIdle AS [System Idle Process],
100 - SystemIdle - SQLProcessUtilization AS [Other Process CPU Utilization],
DATEADD(ms, -1 * ( @ts_now - [timestamp] ), GETDATE()) AS [Event Time]
FROM
(
SELECT
record.value('(./Record/@id)[1]', 'int') AS record_id,
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') AS [SystemIdle],
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int') AS [SQLProcessUtilization],
[timestamp]
FROM
(
SELECT
[timestamp],
CONVERT(XML, record) AS [record]
FROM
sys.dm_os_ring_buffers
WHERE
ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
AND record LIKE N'%<SystemHealth>%'
) AS x
) AS y
ORDER BY
record_id DESC
OPTION ( RECOMPILE );
O script acima utiliza a DMV sys.dm_os_ring_buffers e o Extended Event “SystemHealth”, habilitado por padrão. Você não precisa ativar nada para utilizar esse script e ele retorna sempre o uso de CPU dos últimos 256 minutos (um pouco mais de 4h). Caso a instância seja reiniciada, esses dados serão perdidos.
Esse script foi testado no Azure SQL Database e SQL Server 2008 e 2019.
Como retornar o uso de Memória utilizando T-SQL
Para retornar o uso de Memória do servidor utilizando T-SQL, utilize o script abaixo. Com ele, é possível identificar se está havendo pressão de memória e se ela está sendo causada pelo SO ou pelo próprio SQL Server.
O primeiro ponto que deve ser observado, é a coluna “RmNotification”, que nos indica o tipo de notificação gerada:
- RESOURCE_MEMPHYSICAL_HIGH – SQL tem espaço para alocar mais memória
- RESOURCE_MEMPHYSICAL_LOW – Memória física interna ou de sistema baixa
- RESOURCE_MEM_STEADY
- RESOURCE_MEMVIRTUAL_LOW – Range de endereços virtuais para o SQL Server estão se esgotando
Se a coluna “RmNotification” apresentar uma mensagem de “RESOURCE_MEMPHYSICAL_LOW”, quer dizer que a memória estava baixa e isso gerou esse alerta na Ring Buffer.
Para entender o que estava baixo, vamos observar as colunas “IndicatorsProcess” e “IndicatorsSystem”.
Se a coluna “IndicatorsProcess” retornar 0 e a coluna “IndicatorsSystem” retornar um valor diferente de 0, quer dizer que o problema de pressão de memória afetou todo o sistema. Mas se o contrário acontecer, quer dizer que somente um processo que sofreu pressão de memória e não o sistema todo (mas não fala qual processo foi).
Possívels valores para as colunas “IndicatorsProcess” e “IndicatorsSystem”:
- IDX_MEMPHYSICAL_HIGH (High Physical Memory) = 1
- IDX_MEMPHYSICAL_LOW (Low Physical Memory) = 2
- IDX_MEMVIRTUALL_LOW (Low Virtual Memory) = 4
-- https://blogs.msdn.microsoft.com/mvpawardprogram/2012/06/04/using-sys-dm_os_ring_buffers-to-diagnose-memory-issues-in-sql-server/
WITH RingBuffer AS (
SELECT
CAST(dorb.record AS XML) AS xRecord,
dorb.[timestamp]
FROM
sys.dm_os_ring_buffers AS dorb
WHERE
dorb.ring_buffer_type = 'RING_BUFFER_RESOURCE_MONITOR'
)
SELECT
xr.value('(ResourceMonitor/Notification)[1]', 'varchar(75)') AS RmNotification,
DATEADD (ss, (-1 * ((B.cpu_ticks / CONVERT (FLOAT, (B.cpu_ticks/ B.ms_ticks))) - A.[timestamp]) / 1000), GETDATE()) AS RmDateTime,
xr.value('(ResourceMonitor/IndicatorsProcess)[1]', 'tinyint') AS IndicatorsProcess,
xr.value('(ResourceMonitor/IndicatorsSystem)[1]', 'tinyint') AS IndicatorsSystem,
xr.value('(MemoryNode/TargetMemory)[1]', 'bigint') AS TargetMemory,
xr.value('(MemoryNode/ReserveMemory)[1]', 'bigint') AS ReserveMemory,
xr.value('(MemoryNode/CommittedMemory)[1]', 'bigint') AS CommitedMemory,
xr.value('(MemoryNode/SharedMemory)[1]', 'bigint') AS SharedMemory,
xr.value('(MemoryNode/PagesMemory)[1]', 'bigint') AS PagesMemory,
xr.value('(MemoryRecord/MemoryUtilization)[1]', 'bigint') AS MemoryUtilization,
xr.value('(MemoryRecord/TotalPhysicalMemory)[1]', 'bigint') AS TotalPhysicalMemory,
xr.value('(MemoryRecord/AvailablePhysicalMemory)[1]', 'bigint') AS AvailablePhysicalMemory,
xr.value('(MemoryRecord/TotalPageFile)[1]', 'bigint') AS TotalPageFile,
xr.value('(MemoryRecord/AvailablePageFile)[1]', 'bigint') AS AvailablePageFile,
xr.value('(MemoryRecord/TotalVirtualAddressSpace)[1]', 'bigint') AS TotalVirtualAddressSpace,
xr.value('(MemoryRecord/AvailableVirtualAddressSpace)[1]', 'bigint') AS AvailableVirtualAddressSpace,
xr.value('(MemoryRecord/AvailableExtendedVirtualAddressSpace)[1]', 'bigint') AS AvailableExtendedVirtualAddressSpace
FROM
RingBuffer AS A
CROSS APPLY A.xRecord.nodes('Record') record(xr)
CROSS JOIN sys.dm_os_sys_info AS B
Se precisar de uma query mais simples, pode também utilizar a DMV “dm_os_process_memory”:
SELECT *
FROM sys.dm_os_process_memory
Eu já havia compartilhado esses scripts acima no artigo SQL Server – Consultas úteis do dia a dia do DBA que você sempre tem que ficar procurando na Internet, mas a maioria das pessoas acabava não encontrando quando precisava e por isso resolvi criar esse artigo.
Espero que vocês tenham gostado desse post.
Um grande abraço e até mais!



Comentários (0)
Carregando comentários…