web-dev-qa-db-ja.com

同じテーブル内の複数のBITデータ型列

Microsoft SQLのドキュメントページからの次の情報を検討してください。

SQL Serverデータベースエンジンは、ビット列のストレージを最適化します。テーブルに8ビット以下の列がある場合、列は1バイトとして格納されます。 9ビットから16ビットまでの列がある場合、列は2バイトとして格納されます。

参照: https://docs.Microsoft.com/en-us/sql/t-sql/data-types/bit-transact-sql?view=sql-server-2017

したがって、次のような新しいテーブルを作成すると、

CREATE TABLE MyTable (
    Id int PRIMARY KEY,
    Value1 bit,
    Value2 bit,
    Value3 bit,
    Value4 bit,
    Value5 bit,
    Value6 bit,
    Value7 bit,
    Value8 bit)

...次に、1つの行のすべてのビット列(Value1、Value2、... Value8)は1バイトを占める必要があります。それとも?

よく見てみると、行のValue1フィールドは、内部に値0、1、またはNULLを持つことができます。つまり、フィールドは実際にはトライステート値または3値です。そのような2つの値は、3 * 3 = 9の値の辞書を表すことができます。 8個のそのような値は6561個の値の辞書です。

このような行のメモリフットプリントを考えている場合、8ビットは1バイトを占めるはずです。つまり、この1バイトは256値ではなく6561値をエンコードします。これは明らかに間違っています。

したがって、MS SQLドキュメントは誤解を招くものであるか、ここでは量子コンピューティングについて話しています。もちろんそれは前者ですが、私が本当に知りたいのは、この質問に対する答えです:null可能ビットはどのように(そしてもちろん、SQL Serverビットはデフォルトでnull可能です)reallySQL Serverの基本構造に格納されていますか?

固定長フィールド(ビット値など)の場合、フィールドは常に同じ量のスペースを使用します。この場合、1ビットです。

NULLビットマップ はデータ行自体にあります。これは、特定のフィールドがNULLと見なされるかどうかに関係なく格納されます。そのため、フィールド自体は2つの値(1または0)を格納するだけでよく、NULLビットマップは、フィールドが実際にNULLに設定されているかどうかに関係なく処理します。

NULLビットマップは、列がNULL可能かどうかに関係なく、テーブルの各列にビットを持ち、これには、あなたが言及する「3番目の値」が含まれます。ここでも、nullビットマップのスペースは、バイト数の整数に切り上げられます。

次のコードは、SQL ServerがNULLビットマップを格納する方法を示しています。これを自分で実行する場合は、ページ番号を置き換える必要があります。

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

私にとっては、3つのデータ行について次の結果が得られます。

0000000000000000:10000e00 68656c6c 6f202020 20200100 00 .... hello ...

0000000000000000:10000e00 68656c6c 6f322020 20200100 00 .... hello2 ...

0000000000000000:10000e00 68656c6c 6f322020 20200100 01 .... hello2 ...

NULLビットマップは、その最後のバイト値への変更です。リトルエンディアンで読み取ると、バイナリ表現は0000 0001(IE最初の列はNULLです)

興味深いことに、システムが前のINSERTの値を、固定長フィールドの実際のデータとして、0にするのではなく保存したこともわかります。

13
George.Palacios