BIT 列是否为 CCI 提供任何性能优势?

Joe*_*ish 7 sql-server columnstore sql-server-2016

BIT列在聚集列存储索引中使用时是否提供任何性能优势?例如,我对在 CCI 中定义列BIT而不是 所获得的任何性能优势感兴趣BIGINT。我正在使用 SQL Server 2016。

我对 CCI 压缩的工作原理知之甚少,但根据我所阅读的内容和一些测试,似乎数据类型(仅限于存储整数的精确数字)在列存储压缩方面确实无关紧要. 例如,如果我将 10 个完整的行组插入到带有BIGINT列而不是BIT列的表中,我看不到压缩行组之间的大小差异。以下是一项测试的源数据:

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);
Run Code Online (Sandbox Code Playgroud)

插入具有 8BIT列的 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);
Run Code Online (Sandbox Code Playgroud)

插入具有 8BIGINT列的 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);
Run Code Online (Sandbox Code Playgroud)

我们也可以在列存储 DMV 中看到这一点:

cci dmvs

BIT在 CCI 中使用列有一些优点。例如,加载到增量存储中的数据将占用较少的BIT列空间,因为增量存储基本上是未压缩的堆。在查询计划中,估计数据大小的公式基于列的数据类型,而不是磁盘上表的大小。带BIT列的表的总数据大小为 250 MB,带BIGINT列的表的总数据大小为 880 MB。在某些情况下,250 MB 的估计大小可能会导致更好的计划。

BITCCI 色谱柱还有其他性能优势吗?抑或是数据并不重要,只要键入如您使用的是精确的数字,用于存储整数(BITTINYINTSMALLINTINT,或BIGINT)?

小智 2

首先,我们不是在比较类似的数据类型。

位定义为:

整数数据类型,可以采用 1、0 或 NULL 值。

少量

而 BIGINT 是一个较大的整数,默认情况下会消耗大量空间。

这意味着默认情况下 SQL Server 对每个 BIT 列都有统计信息,而只有一组 BIGINT 统计信息。

正如您正确指出的,BIT 列已优化:

SQL Server 数据库引擎优化了位列的存储。如果表中有 8 位或更少位的列,则这些列将存储为 1 个字节。如果存在 9 到 16 位列,则列将存储为 2 个字节,依此类推。

int、bigint、smallint 和tinyint

您甚至考虑采用至少 8 - 10 个二进制值并将它们推入数字中肯定是有原因的。

毕竟,为什么很多只使用 INT 并节省一半的空间呢?自从我上次检查以来,2,147,483,648 是 10 个字符,仅 4 位,而 BIGINT 大约有 19 个字符,从技术上讲,这比 youvspoit 的 BIT 然后进入列的空间要小。

但这忽视了您的数据是什么。BIT 如何回答有关其代表什么的问题?10010 只是一个大于一万的数字,但在二进制中却实际代表着某种东西。如果在“节省”空间中,您在使用数据之前就强制进行转换,那么它仍然有效吗?

但请不要将 BIT 与 Tinyint 或 BIGINT 等数字数据类型混为一谈。它们有两个不同的目的。