是否可以在Postgres中存储1个字节的数字?

时间:2010-06-22 03:49:13

标签: postgresql

我想在Postgres中存储每个记录7个8位整数值。 Pg不提供单字节整数类型,SMALLINT或2字节,是最小的整数数据类型。无论如何我可以存储我的7个8位数字并节省空间吗?

具有7个元素数组的数组类型是否更紧凑?或者,我应该对我的7个数字进行二进制表示(例如,在Perl中使用pack)并将其存储在单个bytea字段中吗?

还有其他建议吗?

7 个答案:

答案 0 :(得分:17)

鉴于PostgreSQL中任何行的开销都是23 bytes(HeapTupleHeaderData),如果你真的非常关心少量空间,那么你可能选择了错误的存储数据的方法。

无论如何,因为所有更复杂的类型都有自己的开销(bytea增加了四个字节的开销,例如,位串5到8),完成你要找的东西的唯一方法是使用bigint(8)字节),数值地移动每个值并将结果进行OR运算。您可以使用bit string operations来简化代码 - 计算为位字符串,然后在存储之前转换为bigint - 或者如果您希望速度更好,则只需手动乘法/添加。例如,以下是如何将两个字节一起存储为两个字节的结构,然后再将它们取回:

int2 = 256 * byte1 + byte2
byte1 = int2 / 256
byte2 = int2 % 256

您可以将相同的想法扩展到以这种方式存储其中的7个。检索开销仍然很糟糕,但实际上你会在这个过程中节省一些空间。但与行标题相比并不是很多。

答案 1 :(得分:4)

pg_catalog.char(另一种表示法 - “char”)类型,它只使用1个字节来存储其值。

select pg_column_size( 'A' );
pg_column_size
----------------
              2
(1 row)

select pg_column_size( 'A'::"char" );
pg_column_size
----------------
              1
(1 row)

答案 2 :(得分:2)

您是否会使用这些值查找记录?

如果是 - 使用像int4这样的普通数据类型(如果使用64位架构,则使用int8)。

如果没有 - 首先问问自己 - 将这些值存储在Pg中有什么意义?你可以使用bytea(复杂的i / o)或bittrings(甚至更复杂的i / o),但有什么意义呢?你将拥有多少亿条记录?您是否确实检查过较小的数据类型使用较少的空间(提示:它没有,请检查它 - 是否涉及数据对齐问题)?您是否认为较小的数据类型更快(不是。实际上,比较两个int2值比32位架构上的两个int4值更复杂)。

答案 3 :(得分:1)

答案 4 :(得分:1)

首先你询问了7个,但现在是6个字节。六个8位值完全对应于MAC地址大小和PostgreSQL的内置类型macaddr。您可以使用MAC语法f.i插入这些字节。 A1-B2-C3-D4-E5-F6。

答案 5 :(得分:1)

我自己没有对它们进行测试,但是有一些扩展;例如http://pgxn.org/dist/tinyint/

答案 6 :(得分:1)

Fill

这是PostgreSQL中的单字节类型,适合-128,127的范围。来自the docs,

  

类型Rectangle(注意引号)与"char"的不同之处在于仅使用一个字节的存储空间。它在系统目录中作为内部使用简单的枚举类型。

您可以将此偏向[-128,127],在写入数据库之前从[0-255]范围内的任何输入中减去128,并在从数据库读取时将其添加回输出。 / p>

"char"

输出的小摘录

char(1)

我们仅使用-- works SELECT (-128)::"char", 127::"char"; -- generates out of range SELECT (-128)::"char"; SELECT 128::"char"; -- Shifts to unsigned range. -- If you're going to be using "char" -- review the results of this query! SELECT x::int AS "inputUnsigned", chr(x) AS "extendedASCII", -- this is the "char" types representation for that input. signed::"char" AS "charRepresentation", signed AS "inputUnsignedToSigned", signed+128 AS "inputUnsignedToSignedToUnsigned" FROM generate_series(1,255) AS gs(x) -- Here we map the input in the range of [0,255] to [-128,127] CROSS JOIN LATERAL ( VALUES (x::int-128) ) AS v(signed); 因为 inputUnsigned | extendedASCII | charRepresentation | inputUnsignedToSigned | inputUnsignedToSignedToUnsigned ---------------+---------------+--------------------+-----------------------+--------------------------------- .... 190 | ¾ | > | 62 | 190 191 | ¿ | ? | 63 | 191 192 | À | @ | 64 | 192 193 | Á | A | 65 | 193 194 | Â | B | 66 | 194 195 | Ã | C | 67 | 195 196 | Ä | D | 68 | 196 ... 因为您无法生成或输出ASCII generate_series(1,255)(PostgreSQL使用cstrings)

chr(0)分机号

Pguint是一个提供两个一字节表示的扩展,

  • NUL(已签名)
  • pguint(未签名)