Mehr als 8060 Byte pro Datensatz???

Wie die ein oder anderen wissen, kann ein Datensatz nur eine Maximale Länge von 8060 Byte erreichen.

Aber warum?

Naja das hängt im ersten Sinne mit den geliebten "Seiten" zusammen.
Nun wird sich der ein oder andere fragen: Was denn für Seiten…

Alle Daten die im SQL Server hinterlegt werden, müssen auch irgendwie gespeichert werden und dies geschieht in den sogenannten Seiten.
Wenn nun ein "Select" ausgeführt wird, müssen diese Seiten zuerst in den Arbeitsspeicher geladen werden um an den Client das Ergebnis des "Selects" zusenden. 
In den Arbeitsspeicher kommen allerdings keine einzelnen Seiten, sondern die sogenannten Blöcke, diese bestehen nämlich aus acht Seiten.

Diese Seiten bestimmen alles, deshalb ist es auch so wichtig sie zu verstehen.

So viel dazu…

Nun ist die Frage woher kommen diese 8060 Byte aus dem Titel?

Seite_thumb1

Dazu müssen wir uns mal den Seitenaufbau anschauen.
In der Grafik ist zu erkennen das eine Seite 8192 Byte hat. Allerdings hat eine Seite auch einen Header in dem schlichtweg "Seiteninformationen" stehen.
Zum Beispiel: Welche Nummer hat meine Seite? Welche Seite kommt nach bzw. vor mir? und vieles mehr.

Diese Headerinfos klauen uns somit 132 Byte.
Das bedeutet man ist an die Grenze von 8060 Byte gebunden pro Datensatz, denn ein Datensatz muss auf eine Seite passen.

WICHTIG: Pro Datensatz nicht pro Spalte!

Das heißt, man kann so viele Spalten erstellen bis man an meine Grenze von 8060 Byte stößt.
Spaltendefinition_Char_thumb3

Kurzes Beispiel:

Nehmen wir an man hat folgende Tabelle mit dem oben verwendeten Datentypen.

Jetzt wird der Speicherbedarf jeder Spalte errechnet (deshalb auch Char, weil Varchar eine variable Länge besitzt).

Rechnung: 50 + 100 + 50 + 60 +50 (Byte) =  310 Byte.
Das bedeute jeder Datensatz würde 310 Byte verbrauchen (hier ist die Grenze von 8060 Byte noch weit entfernt). Diese Addition von Speicherbedarf der einzelnen Spalten darf nie 8060 Byte überschreiten, es sei denn… - dazu gleich mehr.

Außerdem ist zu sagen das eine einzelne Spalte maximal 8000 Byte verbrauchen darf.

Also Char(8060) ist nicht!

Create Table Test
(
  Spalte_1 Char(8020)
)

Das ist das Ergebnis des Create-Statements:

Fehlermeldung_thumb

Oder das:

Create Table Test
(
 Spalte_1 Char(4100),
 Spalte_2 Char(4100)
)

und hier:

Fehlermeldung_2_thumb

Im Zweiten Beispiel wird die Gesamtgröße von 8060 Byte überschritten.

Jetzt wird es spannend, was passiert wenn man im dritten Beispiel das Char durch ein Varchar ersetzt?

Create Table Test
(
 Spalte_1 Varchar(4100),
 Spalte_2 Varchar(4100)
)

Das Ergebnis des Statements:

Erfolgreich_thumb3

Warum hat dieses Statement funktioniert?
Varchar verbraucht nur so viele Bytes wie Zeichen in der Spalte stehen.
Bei der Erstellung der Tabelle wären es in beiden Varchar-Spalten so gut wie null.

Varchar(50) Spalte mit vier Zeichen Inhalt z.B. "Otto" verbraucht hier 4 Byte Speicher.
Char(50) Spalte mit vier Zeichen Inhalt z.B. "Otto" verbraucht hier 50 Byte Speicher.

Nun die Überlegung: Dann "knallt's" halt zur Laufzeit.

Sobald jemand in die beiden Varchar-Spalten 4100 Zeichen einfügt, sollte hier auch der Fehler auftreten.

Ich demonstriere es mal mit einem Code-Beispiel:

Insert into Test
select REPLICATE('###', 1350), REPLICATE('###', 1350)

Mit diesem Statement werden 1350 x drei "Hashes" in beide Spalten eingefügt, was wiederum 4050 Zeichen ergibt.

Es gibt keine Fehlermeldung…
Aber warum?

Zum Test ob sich auch 4050 Zeichen in den Spalten befinden ein Beispiel:

select len(spalte_1) Spalte_1, len(spalte_2) Spalte_2 from test


Die Ausgabe:

Viele-zeichen_thumb2

Das bedeutet hier haben wir die Grenze von 8060 Byte überschritten. Dieses "Event" nennt man "Row Overflow Data".
Mit dieser Row Overflow Data ist es uns Möglich die 8060 Byte Grenze zu überschreiten, allerdings gibt es ein paar Einschränkungen.

Nehmen wir an wir haben nun so einen Fall.

Drei Spalten:

Spalte_1 char(4100) |  Spalte_2 varchar(4100) |  Spalte_3 varchar(4000)

Jetzt werden alle Spalten dementsprechend voll gefüllt. Hier tritt die Row Overflow Data ein. Die SQL Server Database Engine verschiebt die Spalte mit der größten Breite und der Einschränkung der Datentypen (Wichtig: Row Overflow Data funktioniert nur mit varchar, nvarchar, varbinary, sql_variant und benutzerdefinierten CLR Datentypen)
in die Row_Overflow_Data-Zuordnungseinheit, während ein 24-Byte-Zeiger auf der ursprünglichen Seite beibehalten wird.

Dieses Überschreiten der Zeilengröße kann dadurch zu einer Leistungsbeeinträchtigung führen. Bei Abfragen und Auswahlvorgängen, wie z.B. Sortierungen oder Verknüpfungen von großen Datensätzen bewirkt die Row Overflow Data eine Herabsetzung der Verarbeitungsgeschwindigkeit,
weil diese Datensätze nicht asynchron, sondern synchron verarbeitet werden.

Außerdem muss die Länge der einzelnen Spalten weiterhin unter 8000 Byte liegen.
Zusätzlich kann kein gruppierter Index auf eine Spalte gelegt werden die der Row Overflow Data unterliegt.

Diese Fehlermeldung wird dargestellt:

Index_Fehler_thumb5

Einen nicht gruppierten Index zu setzen klappt ohne Probleme!

Es gibt eine dynamische Verwaltungsfunktion um herauszufinden ob die Tabelle von der Row Overflow Data betroffen ist.

SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'Northwind'), OBJECT_ID(N'Test'), NULL, NULL , 'DETAILED');
GO

Das Ergebnis der Verwaltungsfunktion:

physical_stats_thumb6

Kommentare sind geschlossen