首页 > 解决方案 > 更多列,或一列中的更多值 - SQL 数据库?

问题描述

我们有一个包含文章的数据库,从列大小的角度来看,IMO 可以改进(我们有超过 170 列)有很多列,我们只存储一些布尔值(1 或 0)。与其单独使用 COLUMN X、Z、Y、N 之类的东西,不如将所有内容合并到一个名为“XZYN”的列中,其中每个数字代表 XZYN 的状态。

示例:1000 表示 X=true,ZYN=false。当然,这种状态会从我们的代码中解释出来。

这是一个好主意吗 ?

标签: sqlsql-serverperformancequery-optimizationmultiple-columns

解决方案


从存储的角度来看,像这样将数据存储在单个列中会“花费”更多。一bit列(bit当您说“布尔”时,我假设您的意思是 a)的大小非常小,用于存储1000您可能想要的值int。Anint的大小为 4 字节,而 abit的大小(不出所料)只有 1 位,并且多列被分组为 8 组。

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

这意味着如果您有 100bit列,要将其存储为串联字符串,您将需要 10int列或 6bigint列,分别占用 40 或 48 个字节。对于 100bit列,您将只使用 13 个字节(100 / 8 = 12.5 = 13 个 1 字节组)。

将数据存储在单个列中也不是 SARGable,并且搜索它并不简单。您不能划分列或获取余数,因为其他“列”会影响除法和余数。相反,您必须SUBSTRING在添加任何所需的前导零之后使用类似的东西来获得相关字符,这在我看来是相当“丑陋”的。

然而,另一种解决方案(尽管我也不推荐)是使用按位逻辑。这是您为每个位值分配不同倍数然后聚合它们的地方,然后使用按位运算符提取“列”的值。例如,假设您有 8 列 AH。您可以为这些中的每一个分配一个 8 位二进制值的数字:

a = 1 = 2^0
b = 2 = 2^1
c = 4 = 2^2
d = 8 = 2^3
e = 16 = 2^4
f = 32 = 2^5
g = 64 = 2^6
h = 128 = 2^7

因此,如果一行想要 a、c、f 和 g 的值为真,则存储的值将为 1+4+32+64 = 101。然后您可以检查该值是否为真,使用按位 ( &) 运算符:

SELECT CASE V.I & 1 WHEN 0 THEN 0 ELSE 1 END AS A,
       CASE V.I & 2 WHEN 0 THEN 0 ELSE 1 END AS B,
       CASE V.I & 4 WHEN 0 THEN 0 ELSE 1 END AS C,
       CASE V.I & 8 WHEN 0 THEN 0 ELSE 1 END AS D,
       CASE V.I & 16 WHEN 0 THEN 0 ELSE 1 END AS E,
       CASE V.I & 32 WHEN 0 THEN 0 ELSE 1 END AS F,
       CASE V.I & 64 WHEN 0 THEN 0 ELSE 1 END AS G,
       CASE V.I & 128 WHEN 0 THEN 0 ELSE 1 END AS H
FROM (VALUES(101))V(I);

然而,这同样不是 SARGable,但至少使用的存储空间比存储10100110. 但是,如果您永远不会在 中的列上进行过滤WHERE,那么这可能值得探索,但如果您甚至有可能,那么就不要(尽管在两个bit列和按位列上混合使用,这不会'不需要被过滤,可能不会“坏”以减少列数)。

我的诚实意见,坚持原样。如果表真的“太宽”,请考虑将bit列组分开并将它们放入单独的表中,与当前表具有 1 对 1 的关系。


推荐阅读