在 Postgresql 中有效地存储带有许多前导零的小数

Efficiently Store Decimal Numbers with Many Leading Zeros in Postgresql

数字如:

0.000000000000000000000000000000000000000123456

如果不使用 postgres 中可用的数字类型进行大的性能损失,则很难存储。此 question 解决了一个类似的问题,但我觉得它不是一个可以接受的解决方案。目前,我的一位同事将这样的数字四舍五入到小数点后 15 位,并将它们存储为:

0.000000000000001

以便可以使用双精度数字类型,从而防止与移动到十进制数字类型相关的惩罚。对于我的目的来说这么小的数字在功能上或多或少是等价的,因为它们都非常小(并且或多或少意味着相同的东西)。然而,我们正在绘制这些结果,当大部分数据集像这样四舍五入时,它看起来非常愚蠢(图表上的扁平线)。

因为我们要存储数以万计的这些数字并对它们进行操作,十进制数字类型对我们来说不是一个好的选择,因为性能损失太大。

我是一名科学家,我的自然倾向就是将这些类型的数字以科学计数法存储,但 postgres 似乎没有这种功能。我实际上不需要数字的所有精度,我只想保留 4 位左右,所以我什至不需要 float 数字类型提供的 15 位数字。 像这样将这些数字存储在两个字段中的优点和缺点是什么:

1.234 (real)
-40 (smallint)

这相当于 1.234*10^-40?这将允许约 32000 个前导小数,只有 2 个字节用于存储它们,4 个字节用于存储实际值,每个数字总共最多 6 个字节(给我我想要存储的确切数字并且需要更少 space 比现有解决方案消耗 8 个字节)。似乎对这些数字进行排序也会有很大改进,因为您只需要先对 smallint 字段进行排序,然后再对 real 字段进行排序。

What are the advantages and disadvantages of storing these numbers in two fields like this

您必须管理 2 列而不是 1 列。

粗略地说,您要做的是通过存储低精度浮点数来节省 space。如果只需要 4 位精度,可以更进一步,使用 smallint + smallint (1000-9999 + exponent) 节省 2 个字节。使用该格式,您可以将两个 smallint 塞入一个 32 位 int(指数*2^16 + 尾数),这也应该有效。

假设您需要节省存储空间 space and/or 需要超出双精度浮点数的 +/-308 位指数限制。如果不是这样,标准格式就可以了。

您 and/or 您的同事似乎对使用浮点格式可以表示哪些数字感到困惑。

一个double precision(又名float)数至少可以存储15位有效数字,范围从1e-307到1e+308。您必须将其视为科学记数法。删除所有零并将其移动到指数。如果你曾经有过的科学记数法少于 15 位且指数介于 -307 和 +308 之间,它可以按原样存储。

这意味着 0.000000000000000000000000000000000000000123456 绝对可以存储为 double precision,并且您将保留所有有效数字 (123456)。无需将其四舍五入为 0.000000000000001 或类似的值。

浮点数存在十进制数精确表示的众所周知的问题(因为以 10 为基数的十进制数不一定映射到以 2 为基数的十进制数),但这对您来说可能不是问题(这是一个问题如果您需要能够对这些数字进行精确比较)。