Tenez compte des informations suivantes provenant des pages de documentation Microsoft SQL:
Le moteur de base de données SQL Server optimise le stockage des colonnes de bits. S'il y a 8 colonnes de bits ou moins dans une table, les colonnes sont stockées sur 1 octet. S'il y a de 9 à 16 colonnes de bits, les colonnes sont stockées sur 2 octets, etc.
Voir: https://docs.Microsoft.com/en-us/sql/t-sql/data-types/bit-transact-sql?view=sql-server-2017
Donc, si je crée une nouvelle table comme celle-ci:
CREATE TABLE MyTable (
Id int PRIMARY KEY,
Value1 bit,
Value2 bit,
Value3 bit,
Value4 bit,
Value5 bit,
Value6 bit,
Value7 bit,
Value8 bit)
... alors toutes les colonnes de bits (Value1, Value2, ... Value8) sur une ligne doivent prendre un octet. Ou?
Lorsque nous y regardons de plus près, le champ Value1 d'une ligne peut avoir des valeurs 0, 1 ou NULL à l'intérieur. Cela signifie que le champ a en fait une valeur à 3 états ou une valeur ternaire. 2 de ces valeurs peuvent représenter un dictionnaire de 3 * 3 = 9 valeurs. 8 de ces valeurs sont un dictionnaire de 6561 valeurs.
Si nous pensons à l'empreinte mémoire d'une telle ligne, 8 bits devraient prendre un octet. Cela signifie que cet octet code 6561 valeurs au lieu de 256 valeurs. C'est évidemment faux.
Donc, soit les documents MS SQL sont trompeurs, soit nous parlons ici d'informatique quantique. Bien sûr, c'est le premier, mais ce que je voudrais vraiment savoir, c'est la réponse à cette question: comment sont les bits nullables (et bien sûr que les bits SQL Server sont nullables par défaut) vraiment stocké dans les structures sous-jacentes de SQL Server?
Pour un champ de longueur fixe (comme une valeur de bit), le champ prendra toujours la même quantité d'espace - dans votre cas, un bit.
Le bitmap NULL est dans la ligne de données elle-même - ceci stocké si un champ particulier est considéré comme NULL ou non. En tant que tel, le champ lui-même n'a qu'à stocker deux valeurs - 1 ou 0 - le bitmap NULL gère si le champ est réellement défini sur NULL ou non.
Le bitmap NULL a un bit pour chaque colonne de la table indépendamment du fait que la colonne est nullable, et cela contient la "troisième valeur" que vous mentionnez. Encore une fois, l'espace pour le bitmap nul est arrondi à un nombre entier d'octets.
Le code suivant montre comment SQL Server stocke le bitmap NULL - vous devrez remplacer les numéros de page si vous l'exécutez vous-même.
CREATE TABLE TestNullBitmap (
TestText CHAR(10) NULL
)
GO
INSERT INTO [dbo].[TestNullBitmap] ([TestText])
VALUES
('hello'),
('hello2'),
(NULL);
--Grab the page number
DBCC IND ([TestDb],TestNullBitmap,-1);
GO
--Use the page number from DBCC IND
DBCC PAGE ([TestDb],1,631032,3) WITH TABLERESULTS;
GO
Pour moi, j'obtiens les résultats suivants pour les trois lignes de données:
0000000000000000: 10000e00 68656c6c 6f202020 20200100 00 .... bonjour ...
0000000000000000: 10000e00 68656c6c 6f322020 20200100 00 .... bonjour2 ...
0000000000000000: 10000e00 68656c6c 6f322020 20200100 01 .... bonjour2 ...
Le bitmap NULL est le changement de cette dernière valeur d'octet - lu dans Little Endian, la représentation binaire est 0000 0001
(IE La première colonne est NULL)
De manière assez intéressante, vous pouvez également voir que le système a stocké la valeur de l'insertion précédente en tant que données réelles pour le champ de longueur fixe - au lieu de 0.