暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

选择 PostgreSQL 数字格式

原创 谭磊Terry 恩墨学院 2022-07-25
1015

这应该是世界上最简单的事情:您正在对数据进行建模,并且需要为一些数字设立一列,您使用什么类型?

PostgreSQL 提供了许多不同的数字类型,它们都有优点和局限性。你想要的数字类型是:

  • 使用最少的空间存储您的数据
  • 以最小的错误量表示您的数据
  • 使用正确的逻辑处理您的数据

如果您的处理需求可以通过固定大小的类型(整数或浮点)来满足,请选择具有足够范围以适合您的数据的类型。

如果您需要以极高的精度处理数据,或者以精确的精度存储,那么请使用 numeric 数据类型,它没有范围界限和精确存储的,但会以大小和处理速度为代价。

要在磁盘和内存中获得更紧凑的大小,还请仔细查看列的顺序。将小色谱柱装在一起可以产生惊人的收益。

固定尺寸编号

类型越小,数据在磁盘和内存中占用的空间就越少,这是一个巨大的胜利!同时,类型越小,它可以存储的值范围就越窄!

对于整数类型,较小的类型意味着较小的范围:
image.png

请注意,类型既有 SQL 标准名称,也有 PostgreSQL 特定名称,它们对内部存储大小更精确:一个 int2 占用两个字节。

如果您要存储保证在有界范围内的数字,那么使用适合的最小类型是不费吹灰之力的。

对于浮点类型,较小的类型意味着表示的精度较低。
image.png

在计算机内部构成浮点值的位用于表示“符号”、小数和“指数”——基本上是科学计数法中数字的部分(例如 -1.234E10),仅以二进制表示。
image.png

浮点数的真实世界精度取决于指数的大小。如果指数为 1,则可以在 -2^23 和 2^23 (±8388608) 的数字之间以完美的保真度表示 float4 数据。这是一个很大的忠诚度!

可变大小的数字

数字应该永远存在,但我们讨论过的两类类型都有有限范围和有限精度。作为回报,它们提供固定的存储大小和快速计算。

那些需要潜在地精确表示任何数字并在不损失精度的情况下用它们计算的人呢?对于那些人来说 numeric。

numeric 类型通过成为“可变长度类型”(有时简称为“varlena”)而获得了强大的功能。其他 varlena 类型包括 text/ varchar(可以是任意长度)、bytea(可以是任意长度)以及 PostGIS geometry和geography类型。

一个 numeric 类型数据的存储要求是两个字节,可以满足每组四个十进制数字,加上三到八个字节的开销。所以至少有五个字节,即使是像“1”这样简单的东西。像 40 亿这样的数字,作为 integer 类型需要4 个字节,作为 numeric 类型 需要 9 个字节。

数值计算也需要更长的时间,尽管它仍然非常快。让我们对 1000 万个数字进行除法运算:

-- Takes 5 seconds
SELECT sum(a::float8 / (a+1)::float8)
  FROM generate_series(1, 10000000) a;

-- Takes 15 seconds
SELECT sum(a::numeric / (a+1)::numeric)
  FROM generate_series(1, 10000000) a;

四舍五入和表示

人们对精确度和计算有着非常 Dr. Jekyll 和 Mr. Hyde 的态度。一方面,他们可能对精确度相当无视:

SELECT 3.0::float8 * (1.0/5.0);

 0.6000000000000001

“哦,没关系,我把所有东西都四舍五入展示一下!”
但不可避免地,结果会进入其他过程,突然人们变得非常生气:

SELECT 3.0::float8 * (1.0/5.0) <= 0.6;

 f

“为什么这个愚蠢的数据库会为一个琐碎的数学表达式返回错误的答案!”
当系统处理货币时,对计算中的小偏差和适当舍入的表示的严厉反应尤其严重。精确的数学产生精确的结果。

SELECT 3.0::numeric * (1.0/5.0);

 0.600000000000000000000

出于这个原因,PostgreSQL 文档明确建议:

如果您需要精确的存储和计算(例如货币金额),请使用数字类型。

该numeric类型的舍入行为是“远离零”,而双精度和 float 的舍入行为是“接近最接近的偶数值”。

SELECT x,
  round(x::numeric) AS num_round,
  round(x::double precision) AS dbl_round
FROM generate_series(-3.5, 3.5, 1) as x;
  x   | num_round | dbl_round
------+-----------+-----------
 -3.5 |        -4 |        -4
 -2.5 |        -3 |        -2
 -1.5 |        -2 |        -2
 -0.5 |        -1 |        -0
  0.5 |         1 |         0
  1.5 |         2 |         2
  2.5 |         3 |         2
  3.5 |         4 |         4

在终端提示

在终端提示符下工作时,很难判断键入“4.5”会得到什么,但我们可以从舍入行为中看出它是一个数字,因为它是从零开始舍入的。

SELECT round(-4.5);

 -5

我们必须明确类型才能获得一个向偶数舍入的浮点数。

SELECT round(-4.5::float8);

 -4

结论

选择正确的数据类型会对存储开销产生很大影响!对于相同的值,最小的类型可以使用最大的存储空间的25%。

选择正确的数据类型会对正确性产生关键影响!确保您知道如何使用这些值进行计算,以及您的组织对不精确性的容忍度是多少。

选择正确的数据类型会对性能产生影响!精确数学可能比普通计算慢很多倍,所以在使用精确类型时要准备好付出代价。

原文标题:Choosing a PostgreSQL Number Format
原文作者:Paul Ramsey
原文地址:https://www.crunchydata.com/blog/choosing-a-postgresql-number-format

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论