0

该项目需要将二进制数据存储到 PostgreSQL(项目要求)数据库中。为此,我们制作了一个包含以下列的表格:

id   : integer, primary key, generated by client
data : bytea, for storing client binary data

客户端是一个 C++ 程序,在 Linux 上运行。必须插入行(用一大块二进制数据初始化),然后更新(将额外的二进制数据连接到数据字段)。简单的测试表明,这会产生更好的性能。

根据您的输入,我们将让客户端使用并发线程来插入/更新数据(具有不同的数据库连接),或者只有一个数据库连接的单线程。

我们在 PostgreSQL 方面没有太多经验,所以您能否帮助我们提供一些关于可能出现瓶颈的指针,以及使用多线程插入数据是否比使用单线程更好。

谢谢 :)

编辑1:

更详细的信息:

  • 将只有一个客户端访问数据库,只使用一个 Linux 进程
  • 数据库和客户端在同一台高性能服务器上,但这并不重要,无论机器如何,客户端都必须快速,无需额外的客户端配置
  • 我们将每 10 秒获得新的数据流,流将每 0.5 秒提供新的 16000 字节(CBR,但我们可以使用缓冲,并且最多每 4 秒插入一次)
  • 流将持续 10 秒到 5 分钟之间的任何时间
4

1 回答 1

2

如果您使用bytea.

PostgreSQL 的 MVCC 设计意味着 anUPDATE在逻辑上等价于 aDELETE和 an INSERT。当您插入行然后更新它时,发生的情况是您插入的原始元组被标记为已删除,并且写入的新元组包含旧数据和添加数据的连接。

我质疑您的测试方法 - 您能否更详细地解释您如何确定插入然后附加更快?这没有道理。

除此之外,我认为这个问题写得太宽泛,无法真正说出很多用处。你没有提供任何细节或数字;没有二进制数据大小、行数估计、客户端计数估计等的估计。

bytea插入性能与 PostgreSQL 中的任何其他插入性能调整没有什么不同。所有相同的建议都适用:批量处理事务,使用多个并发会话(但不要太多;经验法则是 number_of_cpus + number_of_hard_drives)插入数据,避免事务使用彼此的数据,因此您不需要UPDATE锁,使用async commit 和/或 commit_delay 如果您没有具有安全回写缓存的磁盘子系统(如电池供电的 RAID 控制器等)。

鉴于您在主评论线程中提供的更新统计数据,您想要使用的数据量听起来完全适用于适当的硬件和应用程序设计。如果您必须提交每个进入的块,即使在普通硬盘驱动器上也可以实现峰值负载,因为它每秒需要大约 60 个事务。您可以使用 acommit_delay来实现组提交并显着降低 fsync() 开销,或者synchronous_commit = off如果您可以承受在崩溃的情况下丢失事务的时间窗口,甚至可以使用。

使用回写式缓存存储设备,如电池支持的缓存 RAID 控制器或具有可靠断电安全缓存的 SSD,这种负载应该很容易应对。

我没有为此对不同的场景进行基准测试,所以我只能笼统地说。如果我自己设计这个,我会担心 PostgreSQL 的检查点停顿,并且想确保我可以缓冲一些数据。听起来你可以,所以你应该没问题。

这是我测试、基准测试和负载测试的第一种方法,因为在我看来它可能是最实用的:

每个数据流一个连接,synchronous_commit = off+ a commit_delay

INSERT每条 16kb 记录进入一个临时表(如果可能UNLOGGED,或者TEMPORARY如果你能承受丢失不完整的记录)并让 Pg 同步和分组提交。当每个流结束时,读取字节数组,将它们连接起来,然后将记录写入最终表。

为了获得这种方法的绝对最佳速度,请实现一个bytea_agg聚合函数bytea作为扩展模块(并将其提交给 PostgreSQL 以包含在未来版本中)。实际上,您很可能可以通过读取数据来避免在应用程序中进行 bytea 连接,或者使用相当低效和非线性缩放:

CREATE AGGREGATE bytea_agg(bytea) (SFUNC=byteacat,STYPE=bytea);

INSERT INTO final_table SELECT stream_id, bytea_agg(data_block) FROM temp_stream_table;

您需要确保调整检查点行为,并且如果您使用普通表或UNLOGGED表而不是TEMPORARY表来累积那些 16kb 记录,则需要确保它被非常积极地VACUUM编辑。

也可以看看:

于 2013-01-26T05:47:48.360 回答