插入和更新BYTEA行时可能出现的瓶颈?

时间:2013-01-25 20:41:24

标签: database postgresql concurrency insert locking

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

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

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

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

我们对PostgreSQL没有多少经验,所以你能否帮助我们提供一些关于可能的瓶颈的指示,以及使用多个线程插入数据是否比使用单个线程更好。

谢谢:)

修改1:

更详细的信息:

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

1 个答案:

答案 0 :(得分:2)

如果您使用bytea,那么在插入行然后附加到行时,您应该获得更好的性能。

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

我对您的测试方法有疑问 - 您能否更详细地解释一下您如何确定insert-then-append更快?这毫无意义。

除此之外,我认为这个问题的范围太广了,不能说得太多。你没有提供任何细节或数字;没有估计二进制数据大小,行数估计,客户计数估计等。

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

鉴于您在主评论主题中提供的更新统计信息,您希望使用的数据量通过适当的硬件和应用程序设计完全可行。如果你必须提交每个进入的块,你的峰值负载即使在普通硬盘上也是可以实现的,因为它每秒需要大约60个事务。您可以使用UPDATE来实现组提交并显着降低fsync()开销,如果在崩溃的情况下可以丢失事务的时间窗口,甚至可以使用commit_delay

使用回写式缓存存储设备(如电池备份缓存RAID控制器或具有可靠断电安全缓存的SSD),此负载应易于应对。

我没有对此进行基准测试,所以我只能说一般。如果我自己设计这个,我会关注PostgreSQL的检查点停顿,并希望确保我可以缓冲一些数据。听起来你可以,所以你应该没事。

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

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

commit_delay每个16kb记录进入临时表(如果可能INSERTUNLOGGED,如果你能承受丢失不完整的记录)并让Pg同步并分组提交。当每个流结束时,读取字节数组,连接它们,并将记录写入最终表。

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

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表来累积这些16kb记录,则需要进行确定它是非常积极的TEMPORARY

另见: