考虑我有一个表,其中插入通常有两个字段:
user_id uuid,
date timestamp
我也有一个普通的b树索引(user_id,date)。
这种方法的问题是不能通过postgres并行地对不同的user_id进行插入,因为索引必须按顺序更新,因为它是一棵树,每次插入后都可以重新平衡,所以它必须等到每个特定的插入完成。
我想要的是每个user_id的独立索引,以便插入可以并行完成。有办法吗?
-------编辑:Laurenz Albe的完美答案在下面
答案 0 :(得分:6)
<强>摘要:强>
你低估了B树索引的力量。
B树索引上的多个插入可以并行运行,树永远不会重新平衡。相反,您偶尔会有一个索引页面拆分,只会在一段时间内阻止该页面上的操作。
<强>参考文献:强>
分页的算法在Lehman and Yao的着名论文中描述(对索引内部感兴趣的人必读),PostgreSQL源代码中的nbtree README描述了删除的更多细节。处理完毕。
插入算法的简短说明:
只要索引页面未满,就会插入新条目。这只会导致索引页面的短暂锁定。
如果页面已满,则使用Lehman&amp; amp; Yao算法,一次最多锁定三页。此拆分需要在父页面中新创建的页面的新条目,因此该页面可能也必须拆分,可能会重复到根页面。
仍然需要不超过三个锁,因为这些操作是一个接一个地发生的。
请注意,这样的根页面拆分在索引的生命周期中仅发生3-4次,因为很少有索引超过5个级别。
这样,B树索引的所有分支都具有相同的深度,因此索引始终是平衡的,不需要重新平衡。重新平衡只能在删除条目时很有意思,但PostgreSQL不会这样做(除非它在完全为空时回收索引页)。
有关您问题的其他说明:
使用像您建议的多个索引不会更快 - 如果您必须为每个user_id
创建索引,这会使事情变得更加复杂和缓慢,并且这些索引不能用于无论如何都要搜索。
尽管如此,索引可以缓慢地降低插入速度。如果同时插入和查询数据,这是一个无法避免的问题。如果在您进行批量插入时没有人查询数据,您可以删除索引并在之后重新创建它。