Sql-Server

用於儲存 0 到 100 之間數值的列的最有效數據類型

  • March 12, 2017

在我正在考慮使用的 MySQL DB 上TINYINT (Unsigned)

你會Byte在 SQL Server 上使用嗎?

此答案僅涵蓋 SQL Server。答案取決於您如何定義高效:是空間還是 CPU?兩者之間可以進行權衡。

讓我們首先檢查儲存整數數據的數據類型的文件:

╔═══════════╦══════════════════════════════════════════════════════════════════════════╦═════════╗
║ Data type ║                                  Range                                   ║ Storage ║
╠═══════════╬══════════════════════════════════════════════════════════════════════════╬═════════╣
║ bigint    ║ -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807) ║ 8 Bytes ║
║ int       ║ -2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647)                         ║ 4 Bytes ║
║ smallint  ║ -2^15 (-32,768) to 2^15-1 (32,767)                                       ║ 2 Bytes ║
║ tinyint   ║ 0 to 255                                                                 ║ 1 Byte  ║
╚═══════════╩══════════════════════════════════════════════════════════════════════════╩═════════╝

對於您的數據,您可以使用TINYINT,因為您的所有數據都在 0 到 255 之間,這將使用最少的空間。讓我們通過將 1000 萬行插入到表中進行快速測試,其值平均分佈在 0 到 100 之間。請注意,我們對所有範例表使用 10 列,因為行儲存表的最小行大小為 9 字節。如果我們創建一個只有一列的表,我們會得到誤導性的結果。我正在針對 SQL Server 2016 SP1 進行測試:

DROP TABLE IF EXISTS dbo.X_TINYINT;

CREATE TABLE dbo.X_TINYINT (
   NUM1 TINYINT NOT NULL,
   NUM2 TINYINT NOT NULL,
   NUM3 TINYINT NOT NULL,
   NUM4 TINYINT NOT NULL,
   NUM5 TINYINT NOT NULL,
   NUM6 TINYINT NOT NULL,
   NUM7 TINYINT NOT NULL,
   NUM8 TINYINT NOT NULL,
   NUM9 TINYINT NOT NULL,
   NUM10 TINYINT NOT NULL
);

INSERT INTO dbo.X_TINYINT WITH (TABLOCK)
SELECT TOP (10000000) 
 n.n, n.n, n.n, n.n, n.n
, n.n, n.n, n.n, n.n, n.n
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
CROSS JOIN master..spt_values t3
CROSS APPLY
(
   SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 101
) n (n);

EXEC sp_spaceused 'dbo.X_TINYINT'; -- data size is 198216 KB

如果我對一個有 10SMALLINT列的表執行相同的程式碼,我會得到 297416 KB 的數據大小。根據引用的數據類型的大小差異,我預計差異約為10000000 * 10 * (2 - 1) / 1024 = 97656 KB,因此非常接近預期的大小增加。

根據您的 SQL Server 版本和版本,您可能能夠進一步減少空間使用量。行壓縮首先在 SQL Server 2008 Enterprise 中可用,並且在 SQL Server 2016 SP1 的所有版本中可用。根據算法的描述,我們可能不會通過列的行壓縮來節省很多TINYINT。他們已經使用了最小的一個字節,但是我們應該為數據減少 1% 的空間,因為 0 被優化為不佔用字節。數據類型的元數據成本也可能有所減少。

應用DATA_COMPRESSION = ROW到表後,我得到的數據大小為 187808 KB。

頁面壓縮在與行壓縮相同的版本和版本中可用。頁面壓縮算法在行壓縮之上以其他幾種方式壓縮數據。頁面上有很多重複值,我們可能會看到顯著的儲存增益。

應用DATA_COMPRESSION = PAGE到一個表後,我得到了 109024 KB 的數據大小,這是一個相當大的減少。

只是為了好玩,我們可以在數據為列儲存格式時檢查空間使用情況。列儲存索引是在 SQL Server 2012 中引入的,並在 2014 年和 2016 年進一步改進。這些不應僅用於節省空間的目的。在使用它們之前,您需要仔細研究和測試。根據您的 SQL Server 版本和版本,使用它們也有一些限制。

DROP TABLE IF EXISTS dbo.X_TINYINT_CCI;

CREATE TABLE dbo.X_TINYINT_CCI (
   NUM1 TINYINT NOT NULL,
   NUM2 TINYINT NOT NULL,
   NUM3 TINYINT NOT NULL,
   NUM4 TINYINT NOT NULL,
   NUM5 TINYINT NOT NULL,
   NUM6 TINYINT NOT NULL,
   NUM7 TINYINT NOT NULL,
   NUM8 TINYINT NOT NULL,
   NUM9 TINYINT NOT NULL,
   NUM10 TINYINT NOT NULL
);

CREATE CLUSTERED COLUMNSTORE INDEX CCI_X_TINYINT_CCI ON dbo.X_TINYINT_CCI;

INSERT INTO dbo.X_TINYINT_CCI WITH (TABLOCK)
SELECT TOP (10000000) 
 n.n, n.n, n.n, n.n, n.n
, n.n, n.n, n.n, n.n, n.n
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
CROSS JOIN master..spt_values t3
CROSS APPLY
(
   SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 101
) n (n)
OPTION (MAXDOP 1);

EXEC sp_spaceused 'dbo.X_TINYINT_CCI'; -- data size is 160 KB

我還可以使用 壓縮 CCI COLUMNSTORE_ARCHIVE,我認為它是為不會更改或經常讀取的歷史數據而設計的。將該壓縮選項應用於整個表後,數據大小進一步減少到 88 KB。

行儲存壓縮選項會增加查詢的 CPU 成本。成本的多少取決於您的工作量和數據,但我們可以使用一個簡單的查詢來說明基本概念:

SELECT MAX(NUM1), MIN(NUM1)
FROM dbo.X_TINYINT
OPTION (MAXDOP 1);

經過一次測試後,我得到了 1469 毫秒的未壓縮數據的 CPU 時間測量值,1687 毫秒的行壓縮數據和 2000 毫秒的頁面壓縮數據。我沒有對列儲存數據進行測試,只是因為它們的工作方式不同。MIN在某些情況下,MAX查詢可以在本地聚合,甚至可以通過元數據操作來滿足。

以下是測試表和查詢的結果摘要:

╔═══════════════════╦══════════════════╦══════════════════════╗
║ Table Compression ║ Data Space in KB ║ Query CPU Time in ms ║
╠═══════════════════╬══════════════════╬══════════════════════╣
║ NONE              ║           198216 ║ 1469                 ║
║ ROW               ║           187808 ║ 1687                 ║
║ PAGE              ║           109024 ║ 2000                 ║
║ CCI               ║              160 ║ N/A                  ║
║ CCI ARCHIVE       ║               88 ║ N/A                  ║
╚═══════════════════╩══════════════════╩══════════════════════╝

您將看到的確切結果取決於您的表結構、數據和工作負載。

引用自:https://dba.stackexchange.com/questions/166815