Verlauf der Systemspeichernutzung ermitteln
Die DMV sys.dm_os_ring_buffers, die mit Microsoft SQL Server Version 2005 eingeführt wurde, gehört zu den wenigen, die offiziell nicht dokumentiert ist und in der BOL zu den DMVs zum Betriebssystem steht „..not supported …only for information … not guaranteed …“. Nun, für Applikationen würde ich die DMV als Informationsquelle nicht verwenden, aber ein Blick schadet nicht, vielleicht liefert sie doch interessante Informationen.
Die View selbst ist sehr „flach“, nur 4 Felder:
- ring_buffer_address varbinary(8): Mit der kann ich noch nichts anfangen
- ring_buffer_type nvarchar(60): Eine Typebezeichnung in Klartext
- timestamp bigint: Weder datetime noch rowversion, sondern reine Zahlen
- record nvarchar(2048): Die Daten sehen aus wie XML, sind nur nicht so deklariert
Der Inhalt von „timestamp“ war schnell geklärt, es sind die Ticks (= Millisekunden) seit dem Rechnerneustart, hat also nichts mit @@TIMETICKS zu tun. Über das Feld ms_ticks aus dem DMV sys.dm_os_sys_info kann man den aktuellen Ticks-Stand ermitteln und darüber auf den eigentlichen Zeitpunkt rückrechnen.
Welche Type es (aktuell) gibt, kann mit einer einfachen Abfrage ermitteln:
SELECT ring_buffer_type
,COUNT(*) AS Occured
FROM master.sys.dm_os_ring_buffers
GROUP BY ring_buffer_type
ORDER BY ring_buffer_type
Ergebnis (auf Laptop, der kurz vorher gestartet wurde):
ring_buffer_type | Occured |
RING_BUFFER_MEMORY_BROKER | 6 |
RING_BUFFER_RESOURCE_MONITOR | 1 |
RING_BUFFER_SCHEDULER | 824 |
RING_BUFFER_SCHEDULER_MONITOR | 18 |
RING_BUFFER_XE_BUFFER_STATE | 4 |
RING_BUFFER_XE_LOG | 1 |
Na, das erste, was hier mein Interesse weckt, ist natürlich RING_BUFFER_RESOURCE_MONITOR. Wie schon erwähnt, sehen die Daten in „record“ wie XML aus und in den Datentypen kann man es auch konvertieren. Ein solcher „record“ für einen Resource_Monitor Eintrag sieht so aus:
<Record id="0" type="RING_BUFFER_RESOURCE_MONITOR" time="1261574341">
<ResourceMonitor>
<Notification>RESOURCE_MEMPHYSICAL_HIGH</Notification>
<IndicatorsProcess>0</IndicatorsProcess>
<IndicatorsSystem>1</IndicatorsSystem>
<NodeId>0</NodeId>
<Effect type="APPLY_LOWPM" state="EFFECT_OFF" reversed="0">0</Effect>
<Effect type="APPLY_HIGHPM" state="EFFECT_ON" reversed="0">0</Effect>
<Effect type="REVERT_HIGHPM" state="EFFECT_OFF" reversed="0">0</Effect>
</ResourceMonitor>
<MemoryNode id="0">
<ReservedMemory>1671680</ReservedMemory>
<CommittedMemory>16636</CommittedMemory>
<SharedMemory>0</SharedMemory>
<AWEMemory>0</AWEMemory>
<SinglePagesMemory>2496</SinglePagesMemory>
<MultiplePagesMemory>10232</MultiplePagesMemory>
</MemoryNode>
<MemoryRecord>
<MemoryUtilization>100</MemoryUtilization>
<TotalPhysicalMemory>2086596</TotalPhysicalMemory>
<AvailablePhysicalMemory>832044</AvailablePhysicalMemory>
<TotalPageFile>4416176</TotalPageFile>
<AvailablePageFile>2442676</AvailablePageFile>
<TotalVirtualAddressSpace>2097024</TotalVirtualAddressSpace>
<AvailableVirtualAddressSpace>326988</AvailableVirtualAddressSpace>
<AvailableExtendedVirtualAddressSpace>0</AvailableExtendedVirtualAddressSpace>
</MemoryRecord>
</Record>
Die Namen der Tags sind wie die aus den Speicher Performance Counters von Windows. XML lässt sich in SQL Server ab 2005 prima abfragen und das machen wir mal.
Auf einem Produktiv-System ausgeführt gibt es einige „RESOURCE_MEMPHYSICAL_HIGH“ Einträge; was für einen Server mit laufenden MS SQL Server aber auch nichts Ungewöhnliches ist.
Aber so kann man mit einfachen Mitteln sein System etwas monitoren und das auch noch rückwirkend.
DECLARE @actualTS BIGINT
SET @actualTS = (SELECT ms_ticks FROM sys.dm_os_sys_info)
PRINT @actualTS
SELECT ORB.EventTime
,ORB.Notif
,ORB.AvailPhyMem
,ROUND(CONVERT(float, 100 * AvailPhyMem) / TotalPhyMem, 3) AS PercentAvailable
,ORB.MemUtil
,ORB.ResvMem
,ORB.CommMem
,ORB.recordXml
FROM (SELECT DATEADD(s, EventTs, GETDATE()) AS EventTime
,ORB.recordXml.value('(./Record/ResourceMonitor/Notification)[1]', 'varchar(50)') AS Notif
,ORB.recordXml.value('(./Record/MemoryNode/ReservedMemory)[1]', 'int') AS ResvMem
,ORB.recordXml.value('(./Record/MemoryNode/CommittedMemory)[1]', 'int') AS CommMem
,ORB.recordXml.value('(./Record/MemoryRecord/MemoryUtilization)[1]', 'int') AS MemUtil
,ORB.recordXml.value('(./Record/MemoryRecord/TotalPhysicalMemory)[1]', 'int') AS TotalPhyMem
,ORB.recordXml.value('(./Record/MemoryRecord/AvailablePhysicalMemory)[1]', 'int') AS AvailPhyMem
,recordXml
FROM (SELECT CONVERT(int, (ORB.timestamp - @actualTS) / 1000) AS EventTs
,CONVERT(xml, record) AS RecordXml
FROM master.sys.dm_os_ring_buffers AS ORB
WHERE ORB.ring_buffer_type = N'RING_BUFFER_RESOURCE_MONITOR'
) AS ORB
) AS ORB
ORDER BY EventTime desc