该项目需要将二进制数据存储到PostgreSQL(项目需求)数据库中。为此,我们制作了一个包含以下列的表:
id : integer, primary key, generated by client
data : bytea, for storing client binary data
客户端是一个在Linux上运行的C ++程序。 必须插入行(用一大块二进制数据初始化),然后更新(将其他二进制数据连接到数据字段)。 简单的测试表明,这会产生更好的性能。
根据您的输入,我们将使客户端使用并发线程来插入/更新数据(使用不同的数据库连接),或者只使用一个数据库连接的单个线程。
我们对PostgreSQL没有多少经验,所以你能否帮助我们提供一些关于可能的瓶颈的指示,以及使用多个线程插入数据是否比使用单个线程更好。
谢谢:)
修改1:
更详细的信息:
答案 0 :(得分:2)
如果您使用bytea
,那么在插入行然后附加到行时,您应该获得更好的性能。
PostgreSQL的MVCC设计意味着UPDATE
在逻辑上等同于DELETE
和INSERT
。当您插入行然后更新它时,发生的事情是您插入的原始元组被标记为已删除,并且新元组被写入包含旧数据和添加数据的连接。
我对您的测试方法有疑问 - 您能否更详细地解释一下您如何确定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记录进入临时表(如果可能INSERT
或UNLOGGED
,如果你能承受丢失不完整的记录)并让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
。
另见: