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:
Beispiel für einen Non-Clustered Index auf einem Clustered Index: