sSQL Server ベースの環境で NULL を登録した場合、どのように格納されていたかを忘れていたので、書いておきたいと思います。
SQL Server NULL の取り扱いについては、集計関数 の NULL 値の取り扱いや NULL と UNKNOWN (Transact-SQL) に記載されており、NULL 値については次のように記載されています。
null 値は、通常、認識されないデータ、適用できないデータ、または後から追加されるデータを示します。
SQL Server の NULL 値は インデックス / 統計情報の対象となり、NULL を使用する目的については、私の認識としても上記のとおりです。
NULL を使うべきかどうか / 何らかの初期値を指定するかについては、データの意味と取り扱いに依存しますので本投稿では触れません。
SQL Server ベースの環境の NULL の格納方法
SQL Server ベースの環境では NULL は、列の値として NULL 文字のような文字が格納されるのではなく、「Null bitmap」を使用して、列が NULL なのかのビットマップが格納されます。
NULL を値ではなくビットマップとして格納することのメリットについては Why is the NULL bitmap in a record an optimization? でも触れられていますので、こちらを確認してみても面白いかと。
SQL Server のページ構造については、Microsoft SQL Server 2012 Internals で触れられているので、詳細についてはこれらの書籍を確認してください。
SQL Server のページ構造は 8KB で構成されており、先頭の 96 バイトがページヘッダーとして使用され、それ以降に実レコードの内容が格納されるというのが一般的に把握されている内容となるのではないでしょうか。
ヘッダー以降のレコード格納部分についてもフォーマットが決められており、基本的な部分のみを抜粋すると次のようになります。
- ステータスビット
- 固定長データ
- 列数
- Null Bitmap
- 可変長データのオフセット
- 可変長データ
次のようなデータを登録し、情報の確認を行ってみます。
DROP TABLE IF EXISTS NULLTEST GO CREATE TABLE NULLTEST( C1 int identity primary key, C2 varchar(10), C3 varchar(10), C4 varchar(10), C5 int ) GO INSERT INTO NULLTEST VALUES (1,1,1,999), (1,1,NULL,999), (1, NULL, NULL,999), (NULL, 1, NULL,999), (NULL, NULL, 1,0), (NULL, NULL, NULL, NULL) GO
クエリを実行すると次のようなデータが登録された状態となります。
これが、実データとしてどのようにページ内に格納されるかというと、次のようになります。
Null Bit map は次の箇所となります。
各値をビットマップに直すと次のようになります。
実際の登録内容と bitmap をマッピングすると次のように表現されます。
NULL が設定されている列についてはビットマップとしては 1 が設定され、NULL 以外の値となっている場合は 0 となります。
各列に NULL 値を登録するのではなく、NULL が登録されている列のビットマップを格納することで、ストレージを効率的に使用することにもつながります。
最後の情報が「NULL, NULL, NULL, NULL」で登録を行ったレコードとなります。
C2~C6 が NULL で登録されている場合、可変長データの登録は行われず「0x1e」で「C2 ~ C5 までが NULL として登録されている」ことを表し、「C2~C5 までが NULL であるという表現を 1 バイトで表す」ことができています
NULL ではなく、何らかの既定値を登録した場合は、値が直接登録されるため、値が登録されていないことを表す場合には、初期値ではなく NULL を登録したほうが、ストレージコストを抑えることもできるのではないでしょうか。