我的问题分为两部分。
- 有没有一种方法可以在PostgreSQL中指定数据库的初始大小?
- 如果没有,当数据库随着时间增长时如何处理碎片?
我最近从MSSQL迁移到Postgres,在创建数据库时我们在MSSQL世界中所做的一件事是指定数据库和事务日志的初始大小。这样可以减少碎片并提高性能,尤其是如果事先知道数据库的“正常”大小时。
数据库的性能随着大小的增长而下降。例如,我要处理的工作量通常需要10分钟。随着数据库的增长,这个时间增加了。进行VACUUM,VACUUM FULL和VACUUM FULL ANALYZE似乎无法解决问题。解决性能问题的方法是停止数据库,对驱动器进行碎片整理,然后进行VACUUM FULL ANALYZE,将测试的性能恢复到最初的10分钟。这使我怀疑碎片化是导致我疼痛的原因。
我在Postgres中找不到任何有关保留表空间/数据库空间的引用。我使用的术语错误,因此一无所获,或者在Postgres中有另一种缓解文件系统碎片的方法。
有指针吗?
解决方案
提供的答案有助于确认我开始怀疑的地方。PostgreSQL将数据库存储在多个文件中,这使数据库可以增长而无需担心碎片。默认行为是将这些文件与表数据一起打包到边缘,这对很少更改的表有好处,但对经常更新的表不利。
PostgreSQL利用MVCC提供对表数据的并发访问。在此方案下,每次更新都会创建已更新行的新版本(可以通过时间戳或版本号,谁知道呢?)。旧数据不会立即删除,但会标记为删除。实际删除发生在执行VACUUM操作时。
这与填充因子有何关系?表格默认填充因子100完全填满了表格页面,这又意味着表格页面中没有空间来容纳更新的行,即,更新的行将与原始行放置在不同的表格页面中。如我的经验所示,这对性能不利。由于汇总表的更新非常频繁(最高1500行/秒),因此我选择将填充因子设置为20,即表的20%用于插入的行数据,而80%用于更新数据。尽管这看起来可能过多,但为更新的行保留的大量空间意味着更新的行与原始行位于同一页面内,并且在自动清理守护程序运行以删除过时的行时,表页面未满。
为了“修复”我的数据库,我做了以下工作。
- 将摘要表的填充因子设置为20。您可以在创建时通过将参数传递给CREATE TABLE或在事后通过ALTER TABLE来实现。我发出了以下plpgsql命令:
ALTER TABLE "my_summary_table" SET (fillfactor = 20);
- 发出VACUUM FULL,因为这将写入表文件的全新版本,因此,暗含了使用新的填充因子写入新的表文件的情况。
重新运行测试,即使数据库足够大以容纳数百万行,我也看不到性能下降。
TL; DR-不是文件碎片造成的,而是表空间碎片造成的。通过调整表格的填充因子以适合您的特定用例,可以缓解这种情况。