sql - 更多列,或一列中的更多值 - SQL 数据库?
问题描述
我们有一个包含文章的数据库,从列大小的角度来看,IMO 可以改进(我们有超过 170 列)有很多列,我们只存储一些布尔值(1 或 0)。与其单独使用 COLUMN X、Z、Y、N 之类的东西,不如将所有内容合并到一个名为“XZYN”的列中,其中每个数字代表 XZYN 的状态。
示例:1000 表示 X=true,ZYN=false。当然,这种状态会从我们的代码中解释出来。
这是一个好主意吗 ?
解决方案
从存储的角度来看,像这样将数据存储在单个列中会“花费”更多。一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 的关系。
推荐阅读
- ios - TVILocalParticipant 代表永远不会被调用
- arrays - 仅更改数组中第一个匹配对象的值
- html - 抓取网页 vba oncick
- linux - 如何在 Pymol 中改变角度?
- mysql - 以 # 符号开头的文本未插入到数据表中
- spring - Tomcat 在 http://localhost:8080/ 中工作,但在尝试 http://localhost:8080/page/home.jsp 时不起作用
- r - 从内部函数覆盖父函数中的变量而不在父函数外部创建变量
- c# - Azure 函数无法加载“System.UriTemplate”
- wordpress - WordPress 通过 .htaccess 强制执行 https
- ios - 从iphone中提取文件日志