Stockage SQL SERVER de TinyInt

12

Dans SQL Server, pourquoi une minuscule est-elle stockée avec 9B dans la ligne. Pour une raison quelconque, il semble y avoir un octet supplémentaire à la fin du masque bitmap NULL.

    USE tempdb;
    ALLER

    CRÉER TABLE tbl
    (
        i TINYINT NOT NULL
    );
    ALLER

    INSÉRER DANS tbl (i)
        VALEURS (1);
    ALLER

    DBCC IND («tempdb», «tbl», - 1);
    ALLER

    DBCC TRACEON (3604); - Le vidage de page ira à la console
    ALLER

    PAGE DBCC («tempdb», 1 168,3);
    ALLER

Résultats (j'ai inversé les octets car DBCC PAGE affiche d'abord l'octet le moins significatif):

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!?)
sans fil
la source
1
Est-ce juste éducatif? Je suis tout à fait pour rogner l'espace là où c'est nécessaire, mais ce n'est probablement pas le 1 octet dont je vais m'inquiéter ...
Aaron Bertrand
C'est éducatif. Ma prochaine conférence SQLSaturday est sur la compression; J'ai donc créé des exemples pour chaque type de données pour aider les gens à comprendre les implications de leurs choix de type de données et pour montrer l'effet de la compression sur tous les types de données.
ooutwire
J'ai supposé que tinyint serait stocké comme 1B (c'est le cas) avec 7B de surcharge. Je me demande quel est l'octet supplémentaire à la fin de l'enregistrement ???
ooutwire
Je vois des résultats différents (mais je ne sais pas s'ils sont plus conformes à ce que vous attendez) lorsque la colonne TINYINT n'est pas la seule colonne du tableau. On dirait un cas d'utilisation assez rare.
Aaron Bertrand
Certainement pas une préoccupation commune de cas d'utilisation. J'essayais simplement de montrer chaque type de données seul pour ramener à la maison les frais généraux impliqués dans le stockage et pour permettre aux débutants de voir à quoi ressemble la colonne sur la page. Je trouve étrange d'avoir l'octet supplémentaire ... me rend fou de le voir là-bas et sans raison.
ooutwire

Réponses:

12

Si vous calculez l'enregistrement en utilisant la simple addition de taille, vous obtenez en effet 8: 4 + 1 + 2 + 1 (en-tête + taille fixe + nombre de bitmap nul + bitmap nul lui-même). Mais un enregistrement de segment ne peut pas être plus petit que la taille du stub de transfert , qui est de 9 octets, car l'enregistrement doit garantir qu'il peut être remplacé par un stub de transfert. Par conséquent, l'enregistrement aura en fait 9 octets. A smallintsera de 9 octets à la fois au moyen du calcul et de la taille min. Tout ce qui est plus grand est déjà plus grand que le talon de transfert, donc la taille de votre calcul correspond à la taille de l'enregistrement.

Remus Rusanu
la source
Les 9 octets s'appliquent également à cette définition CREATE TABLE tbl (i TINYINT NOT NULL PRIMARY KEY), est-ce donc juste une règle générale pour toutes les lignes, qu'elles fassent ou non partie d'un tas?
Martin Smith
1
L'arbre b peut être transformé en tas ( alter table ... drop constraint) et l'opération n'est pas une reconstruction complète (les pages supérieures de l'arbre b sont supprimées, les pages feuilles restantes ne sont pas liées et le résultat est le tas), donc la logique de réservation s'applique toujours .
Remus Rusanu
Je pense que cela prouve ce que Remus a déclaré ... améliorez.dk
archive
6

C'est agréable d'avoir l'oreille de l'auteur. :-) Kalen soupçonne que ce n'est que l'application d'une sorte de longueur de ligne minimale, où tout <9 est ramené à 9. Bien sûr, il n'y a que quelques cas où cela est possible. Vous trouverez cet octet fantôme pour TINYINT et BIT ainsi que VARCHAR (1) / CHAR (1). Il n'augmentera pas au-delà de 9 si vous passez à SMALLINT ou CHAR (2), mais il augmentera si vous passez, disons, à CHAR (3).

Donc, essentiellement, vous pouvez souligner les gains d'efficacité que vous pouvez gagner en choisissant judicieusement les types de données, mais faites remarquer qu'il existe des cas limites où les règles ne tiennent pas en raison d'autres facteurs au niveau de la couche de stockage.

EDIT J'espère avoir des informations plus concrètes pour vous. Je voulais juste vous faire savoir que c'est ce que pense actuellement l'auteur du livre Internals. Elle n'est pas sûre à 100%.

Aaron Bertrand
la source
Merci Aaron d'avoir tendu la main à Kalen. J'ai fouillé ce livre hier soir et j'ai arraché mes cheveux. C'est un peu comme les octets de métadonnées supplémentaires pour sql_variant, sauf qu'ici je n'ai aucun moyen d'expliquer l'octet fantôme sauf pour agiter la main et crier "C'est comme ça que c'est pal!"
ooutwire
1
Eh bien, vous pouvez coupler ce commentaire avec "c'est un cas extrême, car peu de tables sont conçues pour essayer de stocker un seul tinyint ou char (1) dans chaque ligne."
Aaron Bertrand