PostgreSQL:BYTEA与OID+大对象相比如何?

13

我使用 Hibernate 3.2 和 PostgreSQL 8.4 开发了一个应用程序。其中有一些字段是 byte[] 类型,被映射为 @Basic (PG bytea),另一些则被映射为 @Lob (PG Large Object)。为什么会存在这种不一致的情况呢?因为我当时还是一个 Hibernate 新手。

现在,这些字段最大只有 4KB(平均大小为 2-3 KB)。PostgreSQL 的文档提到,当字段很大时使用 LOs 更好,但我没有看到 'big' 的具体含义。

我已经升级到了使用 Hibernate 3.6 和 PostgreSQL 9.0,并将注释更改为 @Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")。这个 bug 引发了潜在的兼容性问题,我最终发现与普通字段相比,处理大型对象确实很麻烦。

因此,我考虑将所有内容都更改为 bytea。但我担心 bytea 字段使用十六进制编码,因此在编解码时会有一些开销,可能会影响性能。

关于这两种方法的性能,是否有好的基准测试结果呢?有人切换过来后发现了差异吗?


1
大对象的一个注意事项 - 由于所有块共享同一个系统表,因此您可以存储的总量限制比 bytea 更低。 - OrangeDog
根据它们的不同,lo_compat_privileges 可能会解决兼容性问题。 - OrangeDog
4个回答

8

基本上每种情况都有适用的情况。bytea 更简单,通常更受青睐。客户端库提供解码功能,所以这不是问题。

然而,LOBs有一些很棒的特性,比如能够在其中寻找并将LOB视为字节流而不是字节数组。

"大"意味着"足够大,你不想一次性将其发送给客户端"。技术上,bytea限制为1GB压缩和lob限制为2GB压缩,但实际上你首先会遇到另一个限制。如果它足够大,你不希望将其直接放入结果集,并且你不想一次性将其发送给客户端,请使用LOB。


我假设大对象被压缩,就像TOASTed的bytea列一样? - OrangeDog

5

但我担心bytea字段是以十六进制编码的。

bytea输入可以是十六进制或转义格式,这取决于您的选择。存储将保持不变。从9.0版本开始,默认输出为十六进制,但您可以通过编辑参数 bytea_output 来更改此设置。

我还没有看到任何基准测试。


此外,它不以十六进制存储,我认为libpq(甚至协议)都有二进制传输的接口。 - Chris Travers

4

简言之,使用bytea

除非您需要流处理或大于1GB的值


Bytea:一个字节序列,像其他可TOAST的值一样工作。每个值限制为1GB,每个表限制为32TB。

大对象:二进制数据分成多行。支持类似操作系统文件的查找、读取和写入,因此操作不需要一次性将所有内容加载到内存中。每个值限制为4TB,每个数据库限制为32TB。


大型对象有以下缺点:

  1. 每个数据库只有一个大型对象表。

  2. 当“拥有”记录被删除时,大型对象不会自动删除。请参阅lo模块中的lo_manage函数。

  3. 由于只有一个表,必须逐条处理大型对象权限。

  4. 流式传输很困难,并且客户端驱动程序对简单的bytea支持更少。

  5. 它是系统模式的一部分,因此您对分区和表空间等选项的控制受到限制。


我敢说,93%的大型对象在实际应用中使用 bytea 会更好。


我在文档中读到,大对象允许大小高达4TB的值。它还承认,“TOAST”存储方式使大对象部分过时。 - Ola
谢谢,@Ola,你是正确的。2GB的限制是旧的。我已经更新了答案。 - Paul Draper

1

我没有大对象和bytea的比较方便,但请注意,在9.0中切换到十六进制输出格式也是因为它比以前的自定义编码更快。就二进制数据的文本编码而言,您可能不会比当前的速度更快。

如果这对您来说还不够好,您可以考虑在PostgreSQL客户端和服务器之间使用二进制协议。然后,您基本上可以像大对象一样直接从磁盘获取内容。我不知道PostgreSQL JDBC是否已支持该协议,但快速搜索表明尚未支持。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接