如果您使用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
编辑。
也可以看看: