Heap or not to Heap, das ist die Frage. Wenn man sich für einen Heap als Datenspeicher entscheidet, ist es wichtig, die Systemstrukturen zu kennen, mit denen Microsoft SQL Server die Daten verwaltet. Dieser Artikel beschäftigt sich mit den – für Heaps relevanten – internen Strukturen einer Datenbank, die wichtig sind, um Vor- und Nachteile von Heaps für die einzelnen Anwendungsszenarien zu erkennen.

PFS-Seite

Eine Datenseite ist die grundlegende Einheit für die Speicherung von Daten in SQL Server. Eine PFS-Seite (Page Free Space) zeichnet auf, ob eine einzelne Seite zugewiesen wurde. Ebenfalls – und das gilt ausschließlich für Heaps – wird der belegte Speicherplatz für eine Datenseite protokolliert.

Vergleicht man einen Heap mit einem Index, kann man sich vorstellen, warum nur für Heaps diese Einschränkung gilt. Sobald Microsoft SQL Server neue Daten in einen Heap eintragen soll, muss Platz gesucht werden, wo die Daten gespeichert werden können. Für Indizes muss der freie Speicherplatz einer Seite nicht nachverfolgt werden, da der Platz für neue Zeilen durch das Schlüsselattribut festgelegt wird.

Informationen aus PFS-Seite
Informationen aus PFS-Seite (Auszug)

Konzeptionell ist jede Datenbankdatei in PFS-Intervallen aufgeteilt. Ein PFS-Intervall besteht aus 8.088 Datenseiten (64 MB). Anders als andere Systemseiten verwendet eine PFS keine Bitmaps sondern Bytemaps für die Verwaltung von Informationen.

Konzeptioneller Aufbau von PFS-Seiten
Eine PFS-Seite verwaltet 8.088 Datenseiten (64 MB)

Eine PFS-Seite verwendet 1 Byte für jede Datenseite und zeichnet unter anderem auf, zu wie viel Prozent die Seite gefüllt ist. Die Speicherung des Füllgrads einer Seite kann bei einem Heap das Bottleneck für eine erfolgreiche Implementierung sein. Microsoft SQL Server kennt für den Füllgrad nur 5 Zustände.

Status (Bits)FüllgradBytes
0x000%0 Bytes
0x01>0% und <=50%1 Byte – 4.030 Bytes
0x02>50% und <= 80%4.031 Bytes – 6.488 Bytes
0x03>80% und <= 95%6489 Bytes – 7.657 Bytes
0x04>95%7.658 Bytes – 8.060 Bytes

Arbeitsweise von PFS-Seite

Das nachfolgende Beispiel zeigt das Zusammenspiel von PFS-Seite und Datenmanipulationen. Detaillierte Erläuterungen zu den einzelnen DML-Operationen werden in späteren Artikeln beschrieben.

-- Erstellen eines Heaps mit einer Satzlänge von
-- 4 Bytes + 400 Bytes + 7 Bytes = 411 Bytes
CREATE TABLE dbo.demo_table
(
	Id	INT			NOT NULL	IDENTITY(1, 1),
	C1	CHAR(400)	NOT NULL	DEFAULT ('Test')
);
GO

Wird in die Tabelle ein neuer Datensatz eingetragen, können die verschiedenen Schritte aus dem Transaktionsprotokoll ausgelesen werden.

BEGIN TRANSACTION InsertRecord
GO
	INSERT INTO dbo.demo_table DEFAULT VALUES;

	SELECT	Operation,
			Context,
			AllocUnitName,
			[Page ID]
	FROM	sys.fn_dblog(NULL, NULL)
	WHERE	[Transaction ID] =
			(
				SELECT	[Transaction ID]
				FROM	sys.fn_dblog(NULL, NULL)
				WHERE	[Transaction Name] = N'InsertRecord'
			)
			OR [Transaction ID] = N'0000:00000000'
	ORDER BY
		[Current LSN] ASC;
	GO
COMMIT TRANSACTION;
GO
Transaktionsprotokoll für einen INSERT Prozess

Nachdem ein neuer Datensatz auf die Seite 142 (0x8e) eingetragen wurde, hat sich der Füllgrad der Datenseite geändert. Diese Änderung wird in Schritt 7 in der PFS-Seite (0x01) dokumentiert.

DBCC TRACEON (3604);
DBCC PAGE (0, 1, 1, 3);
Datenseite belegt 50% des verfügbaren Datenvolumens

Berücksichtigt man die weiter oben genannten Füllgrade, so können insgesamt 9 Datensätze auf der Seite gespeichert werden, bevor erneut eine Aktualisierung der PFS-Seite vorgenommen werden muss.

Acht weitere Datensätze wurden auf der Datenseite erfasst

Der Auszug aus dem Transaktionsprotokoll zeigt, dass während des Einfügeprozesses keine weiteren Aktualisierungen an der PFS-Seite vorgenommen wurden.

Werden weitere 9 Datensätze eingetragen, stellt sich die Transaktion vollkommen anders dar!

Häufige Aktualisierung von PFS-Seite

Sobald der 10. Datensatz auf der Datenseite gespeichert wird (Zeile 6), wird der Status auf der PFS-Seite aktualisiert, da der Grenzwert von 4.030 Bytes überschritten wurde. Der Füllgrad der PFS-Seite wird auf 80% erhöht. Die nächsten 6 Datensätze werden ohne Aktualisierung der PFS-Seite gespeichert, da die gesamte Speichermenge <= 6.576 Bytes ist.

Mit dem nächsten Datensatz wird diese Grenze erneut überschritten und die PFS-Seite wird aktualisiert, da nun 80% der möglichen Speicherkapazität belegt sind. Mit der Speicherung des 17. Datensatzes wird erneut ein Grenzwert überschritten und es ist erneut eine Aktualisierung der PFS-Seite auf 95% erforderlich. Nachdem alle Datensätze gespeichert wurden, stellt sich der Füllgrad der betroffenen Seite wie folgt dar:

95% Füllgrad entsprechen 7.626 Bytes

Der letzte Datensatz wird auf einer neuen Datenseite gespeichert, da er – rechnerisch – nicht mehr auf die Datenseite 142 passt.

8.030 - (8.030 Bytes * 95%) = 401 Bytes

Organisation von Datenseiten in einem Heap

Datenseiten in einem Heap werden ohne Pointer (Referenzen) zur nachfolgenden oder vorherigen Datenseite der Tabelle gespeichert. Diese Referenzen sind in einem Heap nicht erforderlich, da es in der Natur des Heaps liegt, dass es keine vordefinierte Sortierung gibt. Welche Datenseiten zu einem Heap gehören, wird über die IAM-Seite (Index Allocation Map) verwaltet, wie auch alle anderen zeilenbasierten Strukturen (Clustered Index/NonClustered Index).

Um herauszufinden, welche Datenseiten Microsoft SQL Server für die Verwaltung der Tabelle verwendet, kann man die folgende Abfrage verwenden:

SELECT	page_type_desc,
		allocated_page_iam_page_id,
		allocated_page_page_id,
		previous_page_page_id,
		next_page_page_id,
		page_free_space_percent,
		page_level
FROM sys.dm_db_database_page_allocations
(
	DB_ID(),
	OBJECT_ID(N'dbo.demo_table', N'U'),
	0,
	NULL,
	N'DETAILED'
)
WHERE	page_type_desc = N'IAM_PAGE'
ORDER BY
	page_type DESC,
	allocated_page_page_id ASC;
GO

Datenseite 190 verwaltet 4 GB der Tabelle

In der IAM-Seite kann man sehr leicht erkennen, welche Datenseiten zur Tabelle gehören.

DBCC TRACEON (3604);
DBCC PAGE (0, 1, 190, 3);
GO
Datenseiten 3.904 – 3.959 werden von dbo.demo_table verwendet

Wenn Microsoft SQL Server weiß, welche Datenseiten zur Tabelle gehören, können die Daten SEQUENTIELL in ihrer physikalischen Reihenfolge gelesen werden. Diese Technik nennt man „Index Allocation Scan“ und setzt ein paar Erfordernisse voraus, die ich in einem der nächsten Artikel zu Heaps beschreiben werde.

Zusammenfassung

In diesem Artikel habe ich die – für einen Heap – wesentlichen Systemobjekte und Strukturen beschrieben. Sie zu kennen und zu verstehen, ist ein wesentlicher Bestandteil für das Finden einer geeigneten Strategie pro/contra Heap-Strukturen in einer Datenbank.

Herzlichen Dank fürs Lesen!

Bisher erschienene Artikel zum Thema „Heaps“