我们有一个表,记录了近20亿个事件。根据我们的数据模型,每个事件都由4列组合主键唯一标识。除主键外,每个不同的列上都有5个B树索引。因此共有6个B树索引。
该事件记录了数年之久,现在我们需要删除1年以上的数据。
我们有一个time
列,其中记录了每个事件的长值。我们使用以下查询,
delete from events where ctid = any ( array (select ctid from events where time < 1517423400000 limit 10000) )
索引会更新吗?
在测试过程中没有。
插入后,
total_table_size - 27893760
table_size - 7659520
index_size - 20209664
删除后,
total_table_size - 20226048
table_size - 0
index_size - 20209664
答案 0 :(得分:0)
考虑使用@a_horse_with_no_name方法是很好的解决方案。
我们所拥有的:
Postgres版本9.4。
1 table
行,其中2 billion
行与21 columns
(全部bigint
)和5 columns
行合并,主键和5
各个列索引的日期跨度为2年。
它看起来类似于带有time
列的时间序列数据,其中包含UNIX时间戳,但其分析项目除外,因此时间没有有序增加。该表仅是插入和选择的(大多数选择查询使用聚合函数)。
我们需要的:我们的数据跨度为6个月,需要删除旧数据。
我们所做的(对Postgres内部的了解较少): 以10000批处理速率删除行。
初始时,删除ms
是如此之快,因为膨胀增加,每批删除增加到近10s
。然后autovacuum
被触发,并且几乎运行了3 months
。插入率很高,每次删除批次也增加了WAL大小。表格中的统计信息不佳使当前查询变得如此缓慢,以至于它们只能运行数分钟和数小时。
因此,我们决定进行分区。我们在9.4中使用表继承进行了实现。
注意:Postgres从版本10开始Declarative Partitioning,可处理使用表继承进行分区所需的大多数手动工作。
请仔细阅读official docs,因为它们有明确的解释。
简化以及我们如何实现它:
constraint_exclusion
设置为partition
。VACUUM ANALYZE
开始插入新分区后的旧分区。 (在我们的例子中,它帮助查询计划者使用仅索引扫描而不是顺序扫描)time
进行分区,所以我们根据time
值在应用程序级别计算了表名每次插入之前都不会影响我们的插入率。还请阅读此处提到的其他注意事项。
答案 1 :(得分:-1)
可以重新索引
Command: REINDEX
Description: rebuild indexes
Syntax:
REINDEX { INDEX | TABLE | DATABASE | SYSTEM } name [ FORCE ]