web-dev-qa-db-ja.com

BITカラムはCCIにパフォーマンス上の利点を提供しますか?

BIT列をクラスター化列ストアインデックスで使用すると、パフォーマンス上の利点がありますか?たとえば、CCIの列をBITではなくBIGINTとして定義することで得られるパフォーマンス上の利点に興味があります。 SQL Server 2016を使用しています。

私はCCI圧縮のしくみについて非常に限られた理解しか持っていませんが、読んだ内容といくつかのテストに基づいて、データ型(整数を格納する正確な数値に制限されている)は、列ストア圧縮では本当に問題ではないようです。たとえば、BIGINT列ではなくBIT列を含むテーブルに10個の完全な行グループを挿入すると、圧縮された行グループ間のサイズの違いがわかりません。 1つのテストのソースデータは次のとおりです。

DROP TABLE IF EXISTS dbo.CCI_BIT_TEST_SOURCE;

CREATE TABLE dbo.CCI_BIT_TEST_SOURCE (
    ID1 BIGINT NOT NULL,
    ID2 BIGINT NOT NULL,
    ID_BIT BIT NOT NULL,
    ID_BIGINT BIGINT NOT NULL,
    INDEX CCI__CCI_BIT_TEST_SOURCE CLUSTERED COLUMNSTORE
);

INSERT INTO dbo.CCI_BIT_TEST_SOURCE WITH (TABLOCK)
SELECT
  t.RN
, t.RN
, t.RN % 2
, t.RN % 2
FROM
(
    SELECT TOP (10485760) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
    FROM master..spt_values t1
    CROSS JOIN master..spt_values t2
    CROSS JOIN master..spt_values t3
) t
OPTION (MAXDOP 1);

8つのBIT列を持つCCIへの挿入には、平均18729ミリ秒のCPU時間を要しました。テーブルには56960 KBの予約スペースがあります。

DROP TABLE IF EXISTS dbo.CCI_BIT;

CREATE TABLE dbo.CCI_BIT (
    ID1 BIGINT NOT NULL,
    ID2 BIGINT NOT NULL,
    ID_BOOL_1 BIT NOT NULL,
    ID_BOOL_2 BIT NOT NULL,
    ID_BOOL_3 BIT NOT NULL,
    ID_BOOL_4 BIT NOT NULL,
    ID_BOOL_5 BIT NOT NULL,
    ID_BOOL_6 BIT NOT NULL,
    ID_BOOL_7 BIT NOT NULL,
    ID_BOOL_8 BIT NOT NULL,
    INDEX CCI__CCI_BIT CLUSTERED COLUMNSTORE
);

INSERT INTO dbo.CCI_BIT WITH (TABLOCK)
SELECT
  ID1
, ID2
, ID_BIT
, ID_BIT
, ID_BIT
, ID_BIT
, ID_BIT
, ID_BIT
, ID_BIT
, ID_BIT
FROM dbo.CCI_BIT_TEST_SOURCE
OPTION (MAXDOP 1);

8つのBIGINT列を持つCCIへの挿入には、平均18531ミリ秒のCPU時間を要しました。テーブルには、以前と同じ56960 KBの予約スペースがあります。

DROP TABLE IF EXISTS dbo.CCI_NO_BIT;

CREATE TABLE dbo.CCI_NO_BIT (
    ID1 BIGINT NOT NULL,
    ID2 BIGINT NOT NULL,
    ID_BOOL_1 BIGINT NOT NULL,
    ID_BOOL_2 BIGINT NOT NULL,
    ID_BOOL_3 BIGINT NOT NULL,
    ID_BOOL_4 BIGINT NOT NULL,
    ID_BOOL_5 BIGINT NOT NULL,
    ID_BOOL_6 BIGINT NOT NULL,
    ID_BOOL_7 BIGINT NOT NULL,
    ID_BOOL_8 BIGINT NOT NULL,
    INDEX CCI__CCI_NO_BIT CLUSTERED COLUMNSTORE
);

INSERT INTO dbo.CCI_NO_BIT WITH (TABLOCK)
SELECT
  ID1
, ID2
, ID_BIGINT
, ID_BIGINT
, ID_BIGINT
, ID_BIGINT
, ID_BIGINT
, ID_BIGINT
, ID_BIGINT
, ID_BIGINT
FROM dbo.CCI_BIT_TEST_SOURCE
OPTION (MAXDOP 1);

これは、列ストアDMVでも確認できます。

cci dmvs

CCIでBIT列を使用することにはいくつかの利点があります。たとえば、デルタストアは基本的に圧縮されていないヒープであるため、デルタストアにロードされたデータはBIT列で必要なスペースが少なくなります。クエリプランでは、推定データサイズの式は、ディスク上のテーブルのサイズではなく、列のデータ型に基づいています。 BIT列のあるテーブルの合計データサイズは250 MBで、BIGINT列のあるテーブルの合計データサイズは880 MBです。場合によっては、推定サイズ250 MBがより良い計画につながる可能性があります。

CCIのBIT列の他のパフォーマンス上の利点はありますか?または、整数(BITTINYINTSMALLINTINTを格納する正確な数値を使用している限り、データ型は実際には重要ではありませんか、またはBIGINT)?

7
Joe Obbish

まず、類似したデータ型を比較していません。

ビットは次のように定義されます:

1、0、またはNULLの値を取ることができる整数データ型。

[〜#〜]ビット[〜#〜]

一方、BIGINTはデフォルトでかなりの量のスペースを消費する大きな整数です。

つまり、デフォルトでは、SQL Serverは各BIT列の統計情報と、BIGINTの1つのセットのみを持っています。

当然のことながら、BIT列は最適化されています。

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

int、bigint、smallint、およびtinyint

少なくとも8〜10のバイナリ値を取り、それらを数値に入れることを検討している理由があるに違いありません。

結局、なぜINTを使用するだけでスペースを半分節約できるのでしょうか。最後にチェックしてから、2,147,483,648はわずか4ビットで10文字で、BIGINTは約19です。これは技術的には、youvspoitのBITよりスペースが少なく、列に入るスペースです。

しかし、これはあなたのデータが何であるかを見失っています。 BITはそれが何を表しているかについての質問にどのように答えますか? 10010は1万を超える数値ですが、実際には何かを表す2進数です。 「保存」スペースでデータを使用する前に変換を強制している場合でも、それは効率的ですか?

ただし、BITをTinyintやBIGINTなどの数値データ型と混同しないでください。彼らは2つの異なる目的を果たします。

2
clifton_h

CCIのパフォーマンス上の利点はスペースに関連するだけではありません。(サポートされているオペレーターで)バッチ実行モードも高速化に役立ちます。

バッチサイズは64から900行まで変動する可能性があるため、より小さいデータ型を使用すると、「最大」の900に近い「より完全な」バッチが得られると予想するのが妥当です。

https://blogs.msdn.Microsoft.com/sql_server_team/columnstore-index-performance-batchmode-execution/

とにかくデータ型で経済的であることは良い習慣です-tinyint(またはビット)がうまくいくのであれば、なぜbigintを検討するのですか?

1
John Alan