在 JavaScript 中将小数字合并为一个是个好主意吗?(作为存储优化解决方案)

Is it a good idea to combine small numbers into one in JavaScript? (As a storage optimization solution)

本文关键字:好主意 存储 解决方案 优化 一个 合并 数字 JavaScript 小数      更新时间:2023-09-26

据说

javascript 中的所有数字都是 64 位浮点数。

我想知道数字是否总是在内存中使用 64 位?

我有这样的数据结构(在 C 样式代码中(

{
  int x; // [0-9]
  int y; // [0-9]
  int d; // [0-3]
}

x 和 y 将绝对在 [0-9] 范围内,d 的唯一可能值是 0、1、2、3。

如果我将它们存储为 3 位分隔的数字,结构会使用 64 位 * 3 = 192 位 = 24 字节吗?

如果是这样,我想将其存储在一个数字 x * 100 + y * 10 + d 中,这应该只使用 64 位(8 字节(。在不考虑 CPU 使用率的情况下,这更好吗?

我还考虑了字符串解决方案。

x.toString() + y.toString() + d.toString();

因为所有 x、y 和 d 都小于 10,所以它们应该只有 1 个字符,即 16 位。所以结构变成 16 位 * 3 = 48 位 = 6 字节。这是存储优化程度最高的解决方案吗?

那么mongoDB中的存储呢?如果我将数据结构存储到 mongoDB 中,情况是一样的吗?


我写了一个片段来测试mongo中的存储。最终结构包括上述结构的 3 个实例。总金额为66816。

我将它们存储到 3 个单独的数据库中:

  • 布局满(我丢了一个's'(:一个数组包括 3 {x: valueX, y: valueY, d: valueD}
  • layouts-int: xydxydxyd (十进制( ex. 233250750 表示
  • {x:2,y:3,d:3},{x:2,y:5,d:0},{x:7,y:5,d:0}
  • layouts-str:将上面的 int 转换为 2 个字符的字符串。String.fromCharCode(i>> 16( + String.fromCharCode(i & 0xFFFF(

结果是...

> show dbs
layout-full     0.03125GB
layouts-int     0.03125GB
layouts-str     0.03125GB

但细节是...

布局完整的集合

"size" : 8017920,
"avgObjSize" : 120,
"storageSize" : 11182080,

布局中的集合-int

"size" : 2138112,
"avgObjSize" : 32,
"storageSize" : 5591040,

布局中的集合-str

"size" : 2405396,
"avgObjSize" : 36.000299329501914,
"storageSize" : 5591040,

从这些结果中,我发现int存储是最节省空间的方法。

我也这样做了:

> db.tiny.save({})
> db.tiny.stats().avgObjSize
24
> db.tiny.remove()
> db.tiny.save({l:null})
> db.tiny.stats().avgObjSize
28
> db.tiny.remove()
> db.tiny.save({l:[{x:null,y:null,d:null},{x:null,y:null,d:null},{x:null,y:null,d:null}]})
> db.tiny.stats().avgObjSize
84

因此,_id将使用 24 个字节,而关键部分 {l: 将使用 4 = 28 - 24 个字节。

并且你可以发现一个整数使用 32 - 28 = 4 个字节,所以小于 2^31 的整数似乎在 mongo db 中存储为 32 位整数。

同样在字符串解决方案中,一个 2 个字符的字符串使用 36 - 28 = 8 个字节,刚好等于我猜的值。

而对于全结构解决方案,从上一个小数据库测试中,你可以看到没有数据的结构使用 84 个字节,所以数据使用 120 - 84 = 36 字节 = 9 * 4 字节。我的最终数据结构中只有 9 个整数(三重 x,y,d(。这也证明了整数存储为 32 位整数。

为什么空结构使用 84 个字节?

通过更多的实验,我发现 1 个数组或空 json 对象使用 4 个字节,一个键使用 * 4。

所以,空结构实际上是

{                                               // 1 object +4 bytes       = 4
  '_id': ObjectId('0123456789abcdef012345678'), // 3-char key + 12-byte id = 24
  'l': [                                        // 1-char key + 1 array    = 8
    {'x': null, 'y': null, 'd': null},          // 1 object+ 3 keys        = 16
    {'x': null, 'y': null, 'd': null},          // 1 object+ 3 keys        = 16
    {'x': null, 'y': null, 'd': null}           // 1 object+ 3 keys        = 16
  ]
}

结果是 4 + 24 + 8 + 16 * 3 = 84 字节。

我希望我的实验对其他人有用。

这会将三个数字存储在一个字符字符串中。做得更好的唯一方法是使用类型化数组,但我不确定这是这里的一个选项。

function showMeSomeMagic(x, y, d) {
  // we assume that:
  // - x, y are integers in the range [0 9] 
  // - d is an integer in the range [0 3]
  // if not add the appropriate checks/casting/coercing
  var n = (d << 8) + (y << 4) + x;
  // return a String made of a single Unicode code point in 
  // the range [0xE000 0xE399], i.e. inside the Unicode BMP PUA
  return String.fromCharCode( n + 0xE000 );
}
function showMeSomeInverseMagic(s) {
  // we assume that:
  // s is a String created by showMeSomeMagic
  var n = s.charCodeAt(0) - 0xE000;
  var x = n & 15;
  var y = (n >> 4) & 15;
  var d = (n >> 8) & 15;
  return { x:x, y:y, d:d };
}

编辑:根据OP评论更新

相关文章: