SQL Server Closeup #5: Undokumentierter SQL Befehl DBCC PAGE

In diesem Posting möchte ich einen weiteren undokumentierten Befehl des SQL Servers vorstellen.
Heute ist der Befehl DBCC PAGE an der Reihe, mit dessen Hilfe man den Inhalt einer Page darstellen kann.

Da standardmäßig der SQL Server die Ergebnisse des DBCC PAGE nicht an den Client sendet, muss vor dessen Verwendung das Trace Flag 3604 gesetzt werden, um dies zu ändern:

DBCC TRACEON(3604)

Da hierbei nichts gravierendes im SQL Server geändert wird, kann dieser Befehl auch auf Produktivsystemen angewendet werden

 

SQL Syntax des DBCC PAGE Befehls

Der DBCC PAGE Befehl hat 5 Parameter wovon der fünfte Parameter optional ist:

DBCC PAGE ({'dbname' | dbid}
          , filenum
          , pagenum
          [, printopt])

Der erste Parameter erwartet einen Datenbanknamen oder eine Datenbank ID.
Der zweite Parameter erwartet eine File ID.
Der dritte Parameter erwartet eine Page in File ID.
Um sich einen Überblick über die File ID und Page in File ID zu holen, empfehle ich den undokumentierten SQL Befehl DBCC IND [Mehr].
Der vierte Parameter erwartet einen der folgenden Werte:

Wert Funktion
0 Ist der Standardwert und zeigt den Buffer Header und Page Header an.
1 Zeigt den Buffer Header, Page Header, Jede Zeile einzeln und das Row Offset Array an.
2 Zeigt den Buffer Header, Page Header, die Page als Ganzes und das Row Offset Array an.
Es gibt Situationen in denen dieser Parameterwert die einzige Chance darstellt, überhaupt etwas mittels DBCC PAGE angezeigt zu bekommen.
3 Zeigt den Buffer Header, Page Header, Jede Zeile einzeln und das Row Offset Array an.
Hinter jeder einzelne Zeile wird für jeden Spaltewert dieser noch einmal separat angezeigt.

 

Ausgabe des DBCC PAGE Befehls

Print-Option = 1

Die ersten Details der Ausgabe werde ich anhand der Print-Option = 1 darstellen und meine Erklärungen in grün einfügen:

PAGE: (1:80)

BUFFER:

BUF @0x03DC40DC

bpage = 0x137EA000      bhash = 0x00000000           bpageno = (1:80)
bdbid = 10              breferences = 0              bUse1 = 43557
bstat = 0xc0010b        blog = 0xca2159bb            bnext = 0x00000000

Als erstes wird der Buffer Header ausgegeben.
Dieser stellt die aktuelle Verbindung zwischen Arbeitsspeicher 
und physikalischer Page dar.
An dieser Stelle möchte ich mich mit Details zurückhalten...

PAGE HEADER:

Page @0x137EA000

m_pageId = (1:80)       m_headerVersion = 1              m_type = 1
m_typeFlagBits = 0x4    m_level = 0                      m_flagBits = 0x8000
m_objId (AllocUnitId.idObj) = 29     m_indexId (AllocUnitId.idInd) = 256  
Metadata: AllocUnitId = 72057594039828480                                 
Metadata: PartitionId = 72057594038779904                Metadata: IndexId = 0
Metadata: ObjectId = 2105058535      m_prevPage = (0:0)  m_nextPage = (0:0)
pminlen = 12            m_slotCnt = 2                    m_freeCnt = 3202
m_freeData = 4986       m_reservedCnt = 0                m_lsn = (23:111:13)
m_xactReserved = 0      m_xdesId = (0:0)                 m_ghostRecCnt = 0
m_tornBits = 0

Als nächstes wird der Page Header ausgegeben mit folgenden Wertpaaren ausgegeben:

  • m_pageId = Die Page ID der angeforderten Page bestehend aus File ID und Page in File ID.
  • m_headerVersion = Dieser Wert ist seit SQL Server 7.0 immer 1.
  • m_type = Art der Page, wie z.B.

    1 = Data Page 8 = GAM Page 13 = Boot Page
    2 = Index Page 9 = SGAM Page 15 = File Header Page
    3 = TEXT_MIXED_PAGE 10 = IAM Page 16 = DCM Page
    4 = TEXT_TREE_PAGE 11 = PFS Page 17 = BCM Page
  • m_level = Falls es sich um eine Index Page handelt, wird hier die Ebene des Binärbaums angegeben.
    0 steht für den Blattknoten und wird hochgezählt bis zum Stamm.
  • m_flagBits = Ein 2 Byte großer Bereich für weitere Informationen über die Page.
  • m_objId, m_indexId sind noch eine Altlast vom SQL Server 2000 und früher.
    Sie stellten die Verbindung zwischen der Page und dem Object bzw Index dar.
    Seit SQL Server 2005 sollte man die Metadata Werte nehmen.
  • Metadata:AllocUnitId = Die ID der Allocation Unit zu dem diese Page gehört.
  • Metadata:PartitionId = Die ID der Partition zu dem diese Page gehört.
  • Metadata:IndexId = Die ID des Indizes zu dem diese Page gehört.
  • Metadata:ObjectId = Die ID des Objektes zu dem diese Page gehört.
  • m_prevPage = Gibt bei verketteten Index Pages die Page ID der vorherige Page an.
  • m_nextPage = Gibt bei verketteten Index Pages die Page ID der nachgelagerte Page an.
  • pminlen = Die Anzahl der Bytes des Nicht-Variablen-Spalten Teils des Records.
  • m_slotCnt = Die Anzahl der Records, die auf dieser Page gespeichert sind.
  • m_freeCnt = Die Anzahl der freien Bytes der Page.
  • m_freeData = Der Byte Offset (Position) des ersten verfügbaren freien Platzes innerhalb der Page.
  • m_reservedCnt = Die Anzahl der reservierten Bytes aller Transaktionen.
  • m_lsn = Die Log Sequence Number (LSN) des letzten Logeintrages, der diese Page verändert hat.
    Dazu in einem späteren Posting mehr.
  • m_xactReserved = Die Anzahl der reservierten Bytes der zu letzt gestarteten Transaktion.
  • m_ghostRecCnt = Die Anzahl der Ghost Records auf dieser Page.
  • m_tornBits = Eine Bit-Zeichenkette (1 Bit pro Sektor), die für die Torn-Page-Detection genutzt wird.
    Dazu in einem späteren Posting mehr.
Allocation Status GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED 
PFS (1:1) = 0x62 MIXED_EXT ALLOCATED  80_PCT_FULL        DIFF (1:6) = CHANGED 

ML (1:7) = NOT MIN_LOGGED 

In diesem Abschnitt werden verschiedene Informationen zur Speicherverwaltung angezeigt: Der Status der GAM, SGAM, DCM (DIFF) und BCM (ML) Page, ob die Page Teil eines Mixed Extents ist und der ungefähre Füllstand. 

Im darauffolgenden Abschnitt werden die einzelnen Record (hier Primary Records – der interne Name für Data Records) als Hexdump ausgegeben:   

DATA: 

Slot 0, Offset 0x60, Length 2445, DumpStyle BYTE 

Record Type = PRIMARY_RECORD         Record Attributes = NULL_BITMAP VARIABLE_COLUMNS 
Record Size = 2445 
Memory Dump @0x6370C060 

00000000:   30000c00 01000000 01000000 04004002 †0.............@. 
00000010:   0075098d 895a6569 6c65315a 65696c65 †.u .‰Zeile1Zeile 
00000020:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei 
00000030:   6c65315a 65696c65 315a6569 6c65315a †le1Zeile1Zeile1Z 
00000040:   65696c65 315a6569 6c65315a 65696c65 †eile1Zeile1Zeile 
00000050:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei
...Ausgabe an dieser Stelle gekürzt...
00000950:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei 
00000960:   6c65315a 65696c65 315a6569 6c65315a †le1Zeile1Zeile1Z 
00000970:   65696c65 31040000 61010000 00491600 †eile1...a....I.. 
00000980:   00401f00 004e0000 00010000 00††††††††.@...N....... 

Slot 1, Offset 0x9ed, Length 2445, DumpStyle BYTE 

Record Type = PRIMARY_RECORD         Record Attributes = NULL_BITMAP VARIABLE_COLUMNS 
Record Size = 2445 
Memory Dump @0x6370C9ED 

00000000:   30000c00 02000000 02000000 04004002 †0.............@. 
00000010:   0075098d 895a6569 6c65325a 65696c65 †.u .‰Zeile2Zeile 
00000020:   325a6569 6c65325a 65696c65 325a6569 †2Zeile2Zeile2Zei 
00000030:   6c65325a 65696c65 325a6569 6c65325a †le2Zeile2Zeile2Z 
00000040:   65696c65 325a6569 6c65325a 65696c65 †eile2Zeile2Zeile 
00000050:   325a6569 6c65325a 65696c65 325a6569 †2Zeile2Zeile2Zei
...Ausgabe an dieser Stelle gekürzt...
00000950:   325a6569 6c65325a 65696c65 325a6569 †2Zeile2Zeile2Zei 
00000960:   6c65325a 65696c65 325a6569 6c65325a †le2Zeile2Zeile2Z 
00000970:   65696c65 32040000 61010000 00f16d00 †eile2...a....ñm. 
00000980:   00401f00 005a0000 00010000 00††††††††.@...Z....... 

Als Letztes wird das Row-Offset-Array ausgegeben, welches die Zeiger bzw. Einsprungadressen für die auf der Page gespeicherten Records enthält. Dieses Array gibt somit auch die logische Reihenfolge der Records in umgekehrter Reihenfolge vor. 

OFFSET TABLE: 

Row - Offset 
1 (0x1) - 2541 (0x9ed) 
0 (0x0) - 96 (0x60) 

Die einzelnen Printoptionen unterscheiden sich im DATA Teil der Aussgabe.

Als nächstes ein Beispiel für die Print-Option = 2, bei der der Page Hexdump im Ganzen ausgegeben wird: 

DATA: 

Memory Dump @0x6306C000 

6306C000:   01010400 00820001 00000000 00000c00 †.....‚.......... 
6306C010:   00000000 00000200 1d000000 820c7a13 †............‚.z. 
6306C020:   50000000 01000000 17000000 6f000000 †P...........o... 
6306C030:   0d000000 00000000 00000000 03c3ac51 †.............ìQ 
6306C040:   00000000 00000000 00000000 00000000 †................ 
6306C050:   00000000 00000000 00000000 00000000 †................ 
6306C060:   30000c00 01000000 01000000 04004002 †0.............@. 
6306C070:   0075098d 895a6569 6c65315a 65696c65 †.u .‰Zeile1Zeile 
6306C080:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei 
6306C090:   6c65315a 65696c65 315a6569 6c65315a †le1Zeile1Zeile1Z 
6306C0A0:   65696c65 315a6569 6c65315a 65696c65 †eile1Zeile1Zeile 
6306C0B0:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei
...Ausgabe an dieser Stelle gekürzt...
6306C9A0:   65696c65 315a6569 6c65315a 65696c65 †eile1Zeile1Zeile 
6306C9B0:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei 
6306C9C0:   6c65315a 65696c65 315a6569 6c65315a †le1Zeile1Zeile1Z 
6306C9D0:   65696c65 31040000 61010000 00491600 †eile1...a....I.. 
6306C9E0:   00401f00 004e0000 00010000 0030000c †.@...N.......0.. 
6306C9F0:   00020000 00020000 00040040 02007509 †...........@..u 
6306CA00:   8d895a65 696c6532 5a65696c 65325a65 †.‰Zeile2Zeile2Ze 
6306CA10:   696c6532 5a65696c 65325a65 696c6532 †ile2Zeile2Zeile2 
6306CA20:   5a65696c 65325a65 696c6532 5a65696c †Zeile2Zeile2Zeil 
6306CA30:   65325a65 696c6532 5a65696c 65325a65 †e2Zeile2Zeile2Ze 
6306CA40:   696c6532 5a65696c 65325a65 696c6532 †ile2Zeile2Zeile2
...Ausgabe an dieser Stelle gekürzt...
6306D320:   5a65696c 65325a65 696c6532 5a65696c †Zeile2Zeile2Zeil 
6306D330:   65325a65 696c6532 5a65696c 65325a65 †e2Zeile2Zeile2Ze 
6306D340:   696c6532 5a65696c 65325a65 696c6532 †ile2Zeile2Zeile2 
6306D350:   5a65696c 65325a65 696c6532 5a65696c †Zeile2Zeile2Zeil 
6306D360:   65320400 00610100 0000f16d 0000401f †e2...a....ñm..@. 
6306D370:   00005a00 00000100 00000000 00000000 †..Z............. 
6306D380:   00000000 00000000 00000000 00000000 †................ 
6306D390:   00000000 00000000 00000000 00000000 †................
...Ausgabe an dieser Stelle gekürzt...
6306DFC0:   00000000 00000000 00000000 00000000 †................ 
6306DFD0:   00000000 00000000 00000000 00000000 †................ 
6306DFE0:   00000000 00000000 00000000 00000000 †................ 
6306DFF0:   00000000 00000000 21212121 ed096000 †........!!!!í `. 

OFFSET TABLE: 

Row - Offset 
1 (0x1) - 2541 (0x9ed) 
0 (0x0) - 96 (0x60) 

Und auch noch die Print-Option = 3, bei der, wie bei Print-Option = 1, jedes Record Einzeln ausgegeben wird, aber zusätzlich die einzelnen Spalten angezeigt werden:

Slot 0, Offset 0x60, Length 2445 

Record Type = PRIMARY_RECORD         Record Attributes = NULL_BITMAP VARIABLE_COLUMNS 
Record Size = 2445 
Memory Dump @0x6370C060 

00000000:   30000c00 01000000 01000000 04004002 †0.............@. 
00000010:   0075098d 895a6569 6c65315a 65696c65 †.u .‰Zeile1Zeile 
00000020:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei 
00000030:   6c65315a 65696c65 315a6569 6c65315a †le1Zeile1Zeile1Z 
00000040:   65696c65 315a6569 6c65315a 65696c65 †eile1Zeile1Zeile 
00000050:   315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei
...Ausgabe an dieser Stelle gekürzt...
00000950: 315a6569 6c65315a 65696c65 315a6569 †1Zeile1Zeile1Zei 
00000960: 6c65315a 65696c65 315a6569 6c65315a †le1Zeile1Zeile1Z 
00000970: 65696c65 31040000 61010000 00491600 †eile1...a....I.. 
00000980: 00401f00 004e0000 00010000 00††††††††.@...N....... 

Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4 

intCol1 = 1 

Slot 0 Column 2 Offset 0x8 Length 4 Length (physical) 4 

intCol2 = 1 

Slot 0 Column 3 Offset 0x15 Length 2400 Length (physical) 2400 

vcharCol = Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile 1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1Zeile1 

lobCol = [BLOB Inline Root] Slot 0 Column 4 Offset 0x975 Length 24 Length (physical) 24 

Level = 0         Unused = 97         UpdateSeq = 1 
TimeStamp = 373882880 
Link 0 

Size = 8000 RowId = (1:78:0) Slot 1, Offset 0x9ed, Length 2445 

Record Type = PRIMARY_RECORD         Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 2445 
Memory Dump @0x6370C9ED 

00000000:   30000c00 02000000 02000000 04004002 †0.............@. 
00000010:   0075098d 895a6569 6c65325a 65696c65 †.u .‰Zeile2Zeile 
00000020:   325a6569 6c65325a 65696c65 325a6569 †2Zeile2Zeile2Zei 
00000030:   6c65325a 65696c65 325a6569 6c65325a †le2Zeile2Zeile2Z 
00000040:   65696c65 325a6569 6c65325a 65696c65 †eile2Zeile2Zeile 
00000050:   325a6569 6c65325a 65696c65 325a6569 †2Zeile2Zeile2Zei
...Ausgabe an dieser Stelle abgeschnitten.

 

Non-Clustered Index Pages mit Print-Option=3

Ein nettes Feature bei der Anzeige Non-Clustered Index Pages unter der Print-Option = 3 ist, dass der DATA Teil im Grid-View angezeigt wird.

Beispiel für einen Non-Clustered Index auf einem Heap:

DBCC Page Ausgabe bei einem Non-Clustered Index auf einem Heap

Beispiel für einen Non-Clustered Index auf einem Clustered Index:

DBCC Page Ausgabe bei einem Non-Clustered Index auf einem Clustered Index

Check Also

SQL Saturday #409 Rheinland – Slides und Demos

Vergangenen Samstag fand der dritte deutsche SQL Saturday statt. Wie auch im letzten Jahr konnte dafür als Austragungsort die Hochschule Bonn-Rhein-Sieg genutzt werden. Gemeinsam mit Alexander Karl durfte ich dort eine Session zum Thema "SQL Server vs. Azure DocumentDB – Ein Battle zwischen XML und JSON" halten. Die verwendeten Slides und Code Beispiele findet ihr in diesem Blog Post.