SQL SERVER Speicherung von TinyInt

12

Warum wird in SQL Server ein tinyint mit 9B in der Zeile gespeichert? Aus irgendeinem Grund scheint es am Ende der NULL-Bitmap-Maske ein zusätzliches Byte zu geben.

    USE tempdb;
    GEHEN

    CREATE TABLE tbl
    (
        i TINYINT NICHT NULL
    );
    GEHEN

    INSERT IN tbl (i)
        WERTE (1);
    GEHEN

    DBCC IND ('tempdb', 'tbl', - 1);
    GEHEN

    DBCC TRACEON (3604); - Page Dump wird die Konsole gehen
    GEHEN

    DBCC PAGE ('tempdb', 1,168,3);
    GEHEN

Ergebnisse (Ich habe die Bytes umgekehrt, da DBCC-PAGEs das niedrigstwertige Byte zuerst anzeigen):

Record Size = 9B
10000500 01010000 00
TagA = 0x10 = 1B
TagB = 0x00 = 1B
Null Bitmap Offset = 0x0005 = 2B
Our integer column = 0x01 = 1B
Column Count = 0x0001 = 2B
NULL Bitmap = 0x0000 = 2B (what!?)
outwire
quelle
1
Ist das nur lehrreich? Ich bin alle für das Trimmen von Speicherplatz, wenn nötig, aber dies ist wahrscheinlich nicht das 1-Byte, um das ich mir Sorgen machen werde ...
Aaron Bertrand
Das ist lehrreich. Mein nächster SQLSamstag-Vortrag befasst sich mit der Komprimierung. Daher habe ich Beispiele für jeden Datentyp erstellt, um die Auswirkungen der Datentypauswahl zu verstehen und die Auswirkungen der Komprimierung auf alle Datentypen zu veranschaulichen.
Outwire
Ich nahm an, dass tinyint als 1B (es ist) mit 7B Overhead gespeichert würde. Ich frage mich, was das zusätzliche Byte am Ende der Aufzeichnung ist?
outwire
Ich sehe unterschiedliche Ergebnisse (obwohl ich nicht sicher bin, ob sie mehr mit dem übereinstimmen, was Sie erwarten), wenn die Spalte TINYINT nicht die einzige Spalte in der Tabelle ist. Scheint ein ziemlich seltener Anwendungsfall zu sein.
Aaron Bertrand
Sicherlich kein alltäglicher Anwendungsfall. Ich habe nur versucht, jeden Datentyp einzeln darzustellen, um sowohl die mit der Speicherung verbundenen Overhead-Kosten als auch die Darstellung der Spalte auf der Seite für Anfänger zu optimieren. Ich finde es seltsam, das zusätzliche Byte zu haben ... macht mich verrückt, es dort und ohne Grund zu sehen.
Outwire

Antworten:

12

Wenn Sie den Datensatz mit der einfachen Größenaddition berechnen, erhalten Sie in der Tat 8: 4 + 1 + 2 + 1 (Header + feste Größe + Null-Bitmap-Anzahl + Null-Bitmap selbst). Aber ein Haufen Datensatz kann nicht kleiner sein als die Forwarding - Stub Größe , die 9 Byte ist, da der Datensatz muss gewährleisten , dass sie mit einer Spedition Stummel ersetzt werden kann. Daher wird der Datensatz tatsächlich 9 Bytes lang sein. A smallintwird 9 Bytes sein, sowohl durch Berechnung als auch durch minimale Größe. Alles, was größer ist, ist bereits größer als der Weiterleitungsstub, sodass Ihre Rechengröße der Datensatzgröße entspricht.

Remus Rusanu
quelle
Die 9 Bytes gelten auch für diese Definition. CREATE TABLE tbl (i TINYINT NOT NULL PRIMARY KEY)Ist es also nur eine allgemeine Regel für alle Zeilen, ob sie Teil eines Heaps sind oder nicht?
Martin Smith
1
Der B-Baum kann in einen Heap ( alter table ... drop constraint) umgewandelt werden, und die Operation ist keine vollständige Neuerstellung (die oberen Seiten des B-Baums werden weggeworfen, die verbleibenden Blattseiten werden nicht verknüpft und das Ergebnis ist der Heap), sodass die Reservierungslogik weiterhin gültig ist .
Remus Rusanu
Ich denke, das beweist, was Remus gesagt hat ... improve.dk/archive/2011/06/07/…
ooutwire
6

Es ist schön, das Ohr des Autors zu haben. :-) Kalen vermutet, dass dies nur die Durchsetzung einer Art Mindestreihenlänge ist, bei der alles <9 bis 9 aufgefüllt ist. Natürlich gibt es nur wenige Fälle, in denen dies möglich ist. Sie finden dieses Phantombyte für TINYINT und BIT sowie VARCHAR (1) / CHAR (1). Sie steigt nicht über 9 hinaus, wenn Sie zu SMALLINT oder CHAR (2) wechseln. Sie steigt jedoch, wenn Sie beispielsweise zu CHAR (3) wechseln.

Im Wesentlichen können Sie also auf die Effizienz hinweisen, die Sie durch eine sorgfältige Auswahl der Datentypen erzielen können. Es gibt jedoch auch einige Randfälle, in denen die Regeln aufgrund anderer Faktoren auf der Speicherebene nicht gelten.

EDIT Ich hoffe, genauere Informationen für Sie zu haben. Ich wollte Sie nur wissen lassen, dass dies der Autor des Internals-Buches ist. Sie ist nicht 100% sicher.

Aaron Bertrand
quelle
Vielen Dank, dass Sie sich an Kalen gewandt haben. Ich habe letzte Nacht in diesem Buch gebuddelt und mir die Haare ausgerissen. Dies ist ein bisschen wie die zusätzlichen Metadatenbytes für sql_variant, außer dass ich hier keine Möglichkeit habe, das Phantombyte zu erklären, außer wenn ich von Hand winke und schreie: "So ist es, Kumpel!"
Outwire
1
Sie können diesen Kommentar mit "Dies ist ein extremer Randfall, da nicht viele Tabellen darauf ausgelegt sind, in jeder Zeile ein einzelnes tinyint oder char (1) zu speichern."
Aaron Bertrand