对不起,在实际问题之前有很多背景信息,因为我们已经仔细研究了这个问题,并且我想给你完整的背景。
某些上下文:postgres仅索引扫描依赖于可见性映射(VM)。如果页面未在可见性映射中标记为不完全可见,则postgres将获取该页面以确保此事务对数据可见,即使仅执行索引扫描也是如此。不幸的是,这可以大大减慢索引只扫描。索引可能会返回10k行的结果,但索引本身只能跨越50页(就IO而言非常快)。但是,如果未设置VM,则会产生额外的10k堆提取(在IO方面减慢200倍)。
详细信息:https://wiki.postgresql.org/wiki/Index-only_scans#The_Visibility_Map_.28and_other_relation_forks.29
自己尝试:在VACUUM之前和之后,EXPLAIN ANALYZE仅索引查询。您可以看到VACUUM之后的堆提取数量下降(假设您之前在VM中有一些脏页)
已经尝试:我们已经调整了autovacuum,我们经常吸尘。这有很大帮助,但我们想要更快。
问题(最后):在进行仅索引扫描时是否可以跳过堆取?我知道在阅读时我们不会有完美的MVCC,但我们对此感到满意。索引中的数据足够接近,绝对不值得数千个堆提取的开销,以确保我们不会查看稍微陈旧的数据。借用NoSQL中的术语,我们可以使用“最终一致性”读取。
谢谢!
答案 0 :(得分:2)
没有办法在PostgreSQL中做你想做的事情。做一些工作很有意思,不太可能被接受到核心,非常难以进行扩展,并且可能会产生比你预期的更糟糕的副作用。
你基本上必须为PostgreSQL添加DIRTY READ
隔离级别,除了它甚至比那个弱,因为它也可能返回已删除的数据,旧版本的更新行,以及来自唯一索引的多个值。后一个问题可能会对查询规划器造成很大的影响,因为它允许假设来自唯一索引的结果将是唯一的。
我认为这种变化被PostgreSQL核心接受的可能性非常接近零。可能的用例非常有限。
我能够看到合理添加这样一个功能的唯一方法是通过支持原始读取来更容易地从阻塞丢失/损坏和意外删除中恢复。对于堆的seqscans而言,这是最有意义的,而不是仅索引扫描。
以另一种方式解决这个问题可能更有意义,比如数据库顶部的非持久性缓存层(Redis等),您不需要完全新鲜的数据。