我将使用我在不久的将来编写的应用程序运行大量模拟,但围绕此设计我的数据库时遇到了麻烦。
这是它的工作原理。每个模拟有 6 个可以变化的参数,每个参数有大约 10 个选项。所以我们有大约 100 万个排列以某种方式存储在数据库中。我能想到的最简单的方法是为每个参数设置一列,并为我的主键 (ExperimentID) 添加一列。然后,我可以通过执行一个简单的操作直接访问给定实验的参数
SELECT * FROM Parameters WHERE ExperimentID = (givenID)
每个参数都将作为一个 int 存储在数据库中,我的应用程序将在运行时将其解释为必要的参数。
一种更复杂但我认为更快的方法是利用二进制移位的速度。我没有直接存储参数,而是将有关每个参数的信息存储在 4 位无符号整数中。我实际上并不知道整数是如何在数据库中存储的(二进制方式),所以这是主要的障碍。
关于在这种情况下该怎么做的任何建议?此外,我还没有这些列,所以如果我决定使用第一个选项,我将如何使用一组参数的所有排列来填充表格?
为什么您认为将真实数据隐藏到位掩码字段中会更快?您只谈论 100 万行和每行 24 个字节。这真的不多,特别是因为你只做单例/查找操作。
更好的优化是使用
TINYINT
字段(范围为 0 - 255;byte
在 .NET 中)。使用TINYINT
而不是INT
(并假设FILLFACTOR
**为 100)将导致:INT
字段的 287 行这里获得的主要效率是:
2244 条记录的初始查找时间更快。怎么会这样?对于 100 万行,每 8k 数据页 287 行相当于 3484 页,而每 8k 数据页 806 行仅相当于 1240 页。一旦页面被读取以获取第一行的值,它应该保留在缓冲池(即内存)中以供后续查找(即同一数据页上的其他行)。每页更多的行意味着从磁盘读取的页面更少——在这种情况下减少了 2244 页。但是一旦所有页面都在缓冲池中,无论是每页 806 行还是 287 行,查找速度都应该相同。因此,100 万次中的 2244 次查找操作稍快一些。当然还不错,因为此优化没有相关成本,但只是希望将其放在正确的角度来看。
将整个表保存在内存中所需的内存更少。这将使它更有可能保留在内存中。
最后,绝对有可能将这些数据压缩成更小的表示形式。但此时它是每行 10 个字节,没有增加处理/编码的复杂性,所有值都是人类可读的。每行 10 个字节以下没有太多空间,但即使它减少到每行 7 个字节(INT IDENTITY + 参数 3 个字节,这应该是处理这些范围所需的最低要求),我是不确定增加的复杂性是否值得(即规模不经济)。
您可以使用以下内容填充它(假设两个参数为 0 - 4,两个参数为 0 - 7,两个参数为 0 - 9;基于对问题的评论):
上面的查询仅生成 160k 排列,而不是 100 万,再次基于对问题的评论。但是应该很容易弄清楚如何针对六个参数的任意组合的不同值范围调整它。
** FILLFACTOR:行存储在大约 8060 字节的数据页上。较小的行 = 适合该固定大小容器的更多行。
FILLFACTOR
是为新行保留多少空间(在创建/重建索引时)或由于可变长度字段需要更多字节用于新版本的行而占用更多空间的更新。值 100 表示没有保留空间,当前行应占用 8060 的 100%。在这种情况下,只有固定长度的字段,没有乱序插入。我喜欢将测试参数存储在单个
INT
列中的想法。考虑到这一点,我创建了以下测试平台,这可能有助于解释如何使用测试参数创建表,以及稍后如何提取这些值。首先,我们创建 3 个表,用于构建 0-4、0-7 和 0-9 集合。
在这里,我们填充表格:
INT
这是我们将用于存储组合 6 组数字的移位值的表:在这里,我们从上面的 3 个临时表中填充该表:
下一部分展示了如何从单列中将数字提取到 6 个不同的集合中
INT
:由于只有 160,000 行(您建议的排列数),此表仅需要 2.6MB 的存储空间(大约 330 个数据页),包括
IDENTITY
可能需要也可能不需要的列。以上结果的示例
select
是: