我想在Postgres中存储每个记录7个8位整数值。 Pg不提供单字节整数类型,SMALLINT或2字节,是最小的整数数据类型。无论如何我可以存储我的7个8位数字并节省空间吗?
具有7个元素数组的数组类型是否更紧凑?或者,我应该对我的7个数字进行二进制表示(例如,在Perl中使用pack)并将其存储在单个bytea字段中吗?
还有其他建议吗?
答案 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)
您需要查看此处引用的bytea
数据类型:http://www.postgresql.org/docs/8.4/interactive/datatype-binary.html
还有位字符串数据类型:http://www.postgresql.org/docs/8.4/interactive/datatype-bit.html
答案 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
(未签名)