从存储的角度来看,将数据存储在单列中会“花费”更多。 bit 列(我假设您说“bool”时是指bit)的大小非常小,要存储像1000 这样的值,您可能需要int。 int 的大小为 4 字节,而 bit 的大小(不出所料)只有 1 位,并且多列被分组为 8 组。
SQL Server 数据库引擎优化了位列的存储。如果表中有 8 个或更少的位列,则这些列存储为 1 个字节。如果有 9 到 16 位列,则这些列存储为 2 个字节,依此类推。
这意味着,如果您有 100 个 bit 列,要将其存储为串联字符串,您将需要 10 个 int 列或 6 个 bigint 列,分别占用 40 或 48 个字节。对于 100 个 bit 列,您将只使用 13 个字节(100 / 8 = 12.5 = 13 个 1 字节组)。
将数据存储在单个列中也不是 SARGable,而且搜索它也并不简单。您不能划分列或获取余数,因为其他“列”会影响除法和余数。相反,在添加任何所需的前导零后,您必须使用 SUBSTRING 之类的东西来获得相关字符,这在我看来是相当“丑陋”的。
然而,另一种解决方案(尽管我也不推荐)是使用按位逻辑。这是您为每个位值分配不同倍数然后聚合它们的地方,然后使用按位运算符提取“列”的值。例如,假设您有 8 列,A-H。您可以为这些中的每一个分配一个 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 的关系。