在 PostgreSQL 中将字节茶表示为单个整数的最简单方法是啥?

Posted

技术标签:

【中文标题】在 PostgreSQL 中将字节茶表示为单个整数的最简单方法是啥?【英文标题】:What's the easiest way to represent a bytea as a single integer in PostgreSQL?在 PostgreSQL 中将字节茶表示为单个整数的最简单方法是什么? 【发布时间】:2013-06-20 08:36:17 【问题描述】:

我有一个包含 14 字节数据的 bytea 列。 14 个字节的最后 3 个字节包含数据的 CRC 码。我想将 CRC 提取为单个整数以存储在新列中。

我该怎么做呢?

澄清一下,这是用 Java 实现的一种方法:

int crc = ((rawData[len - 3] & 0xff) << 16 |
            (rawData[len - 2] & 0xff) << 8 |
            (rawData[len - 1] & 0xff)) & 0xffffff;

我希望找到一种无需移位的解决方案,即类似于接受 4 个字节并将它们转换为整数的方法。

【问题讨论】:

【参考方案1】:

另一种方法是提取 hex 表示中的最后 6 个字符,添加一个 x 并直接转换:

db=# SELECT ('x' || right('\x00000000000001'::bytea::text, 6))::bit(24)::int;
 int4
------
    1

.. 比 get_byte() 路由短一点,但也是 PostgreSQL 未记录的特性。但是,我引用Tom Lane here:

这依赖于位类型输入的一些未记录的行为 转换器,但我认为没有理由期望它会中断。一个可能 更大的问题是它需要 PG >= 8.3,因为没有文本 在此之前有点演员。

此相关答案中的详细信息:

Convert hex in text representation to decimal number

这假定您的 bytea_output 设置为 hex,这是自 9.0 版以来的默认设置。可以肯定的是,您可以为您的会话测试/设置它:

SET bytea_output = 'hex';

更多:

PostgreSQL 9.X bytea representation in 'hex' or 'escape' for thumbnail images

性能

我在一个有 10k 行的表上运行了一个测试(最好的 10 个)。 get_byte() 实际上在 Postgres 9.1 中要快一点:

CREATE TEMP TABLE t (a bytea);
INSERT INTO t
SELECT (12345670000000 + generate_series(1,10000))::text::bytea;

位移与乘法/加法差不多:

SELECT 
 ('x' || right(a::text, 6))::bit(24)::int                           -- 34.9 ms
,(get_byte(a, 11) << 16) + (get_byte(a, 12) << 8) + get_byte(a, 13) -- 27.0 ms
,(get_byte(a, 11) << 16) | (get_byte(a, 12) << 8) | get_byte(a, 13) -- 27.1 ms
, get_byte(a, 11) * 65536 + get_byte(a, 12) * 256 + get_byte(a, 13) -- 27.1 ms
FROM t

【讨论】:

@CraigRinger:有时候,力量的阴暗面太诱人了。 :) 使用位移而不是乘法不是更有效吗?看我的回答。 @Zoltán:差不多。我添加了一个测试。 确实如此。我现在也测试了。我接受你的回答,因为它提供了一个没有逐字节操作的解决方案,并且显示了它的低效率。 @Zoltán:只有三个字节,转换有点慢。对于更多字节(integer 最多 4 个或 bigint 最多 8 个字节,它开始获胜,因为它的性能是恒定的,而三个 alt 的性能下降。【参考方案2】:
select get_byte(b, 11) * 65536 + get_byte(b, 12) * 256 + get_byte(b, 13)
from (values ('12345678901234'::bytea)) s(b);
 ?column? 
----------
  3289908

【讨论】:

您的示例 bytea 只有 13 个字节长。 我想知道为什么你的计算结果不同。您有一个错字:2^16 = 65536,而不是 65356。【参考方案3】:

如果我们要进行逐字节操作,那么位移可能比乘法更有效。

根据 Clodoaldo Neto 的回答,我会说:

select (get_byte(arm_data, 11) << 16) |
       (get_byte(arm_data, 12) << 8) |
       (get_byte(arm_data, 13))
            from adsb_raw_message;

大家都同意吗?

【讨论】:

效率不高,但它更像是黑客攻击,在我看来更具可读性。【参考方案4】:

如果您想将 CRC 作为单个整数存储在单独的列中,我建议在插入或更新时对其进行转换;然后将其与bytea 的值一起保存。

您可以在应用程序/业务层执行此操作,或使用插入/更新触发器来填充 CRC 列。

【讨论】:

是的,我在业务层执行此操作,因为更改已经实施,但是,数据库已经包含一组有价值的数据,所以我希望创建一个数据库迁移脚本来提取CRC 到新列中。

以上是关于在 PostgreSQL 中将字节茶表示为单个整数的最简单方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PostgreSQL 中将长 NUMERIC 整数转换为位字符串?

如何在php中将字节数组转换为整数?

在更长的字符串中,如何在 PostgreSQL(和/或 Python 3)中将一个字符(例如,'a')和一个变音字符(例如,'U+030A')转换为单个字符('å')[重复]

如何在C ++中将字节数组中的整数转换为数字

在 C# 中将 3 个字节转换为有符号整数

在 DB2 中将位数据的 char 转换为整数