【问题标题】:Why is Bitmap Scan faster than Index Scan when fetching a moderately large percentage of the table in PostgreSQL?为什么在 PostgreSQL 中获取较大比例的表时,位图扫描比索引扫描快?
【发布时间】:2019-09-03 04:27:35
【问题描述】:

位图扫描作者described the difference between Bitmap Heap Scan and Index Scan

普通索引扫描一次从索引中获取一个元组指针, 并立即访问表中的那个元组。位图扫描获取 一次从索引中获取所有元组指针,使用 内存中的“位图”数据结构,然后访问表中的元组 物理元组位置顺序。位图扫描提高了局部性 以更多的簿记开销为代价参考该表 管理“位图”数据结构 --- 并以数据为代价 不再按索引顺序检索,这对您来说无关紧要 查询,但如果你说 ORDER BY 会很重要。

问题:

  1. 当索引已经排序后,为什么要再次对获取的元组指针进行排序?

  2. 如何用位图排序?我知道位图是什么,但我不明白它如何用于排序。

  3. 为什么在获取较大比例的表时它比索引扫描更快?相反,它似乎给进程增加了相当多的计算量。

【问题讨论】:

    标签: postgresql indexing postgresql-performance


    【解决方案1】:

    在典型安装中,Postgres 存储的主干由 8 KB 的数据页组成。每个数据页通常包含许多元组。阅读physical storage in the manual的详细信息。

    位图扫描中的“位图”是一种在数据页桶中收集元组指针的方法。在此过程中必然会丢失索引排序顺序,以支持物理排序顺序。在“有损模式”下(仅当结果太大或workmem 太小以至于即使很小的位图都无法容纳时才会发生)仅保留块编号并丢弃相应的元组索引。

    之后,每个数据页面仅从存储中访问一次,以提取(可能)多个元组并按物理顺序,这对于某些类型的存储也很重要。在有损模式下,必须通过重新检查索引条件来过滤来自每个识别页面的元组;否则可以使用收集的元组索引直接检索元组。

    在索引扫描中,如果多个元组最终存储在同一个数据页面中,则可能必须多次访问每个页面。实际过程更加复杂。相关:

    对于您的问题:

    1. 由于收集命中并将它们逐页读取数据而导致索引排序丢失。

    2. 因此,如果需要排序顺序(例如,ORDER BY),则必须在添加的排序步骤中再次对结果进行排序。

    3. 必须读取的数据页数是影响整体性能的最重要因素。位图索引扫描将该数量减少到最低限度。随着更快的存储,位图索引扫描的好处变得更小。这就是为什么准确的成本设置对于查询规划器做出正确决策至关重要的原因。

    【讨论】:

    • 1) “收集点击”是什么意思? 2)根据作者的描述,它对元组指针进行排序,而不考虑排序顺序的要求(注意引号末尾的警告)。 3)您提到的好处适用于有损模式。访问单个元组而不是整个数据页面的无损模式呢?
    • 1) “收集命中” = 将合格索引元组的 ctid(或只是“有损模式”中的块号)添加到结果位图。 2)您似乎误读了汤姆·莱恩(Tom Lane)帖子的那一部分。 Index 排序顺序总是在位图索引扫描中丢失。 3) Postgres 总是 必须从存储中读取整个数据页,这是原子单元。如果元组索引也是已知的(不仅仅是“有损模式”中的块号),它可以直接寻址数据页中的元组。无论如何,访问每个数据页面一次的好处是存在的。我又澄清了一些。请点击添加的链接了解更多详情。
    • 感谢您的链接,它非常有用。 1)你能详细说明它是如何导致排序丢失的吗? 2)如果查询的结果不需要任何顺序,那么位图扫描中会有排序操作吗?如果是,它是按什么排序的?
    • 1.我认为原始报价已经很清楚了,我对此进行了详细说明。 2.如果查询不需要任何特定排序,则唯一的“排序”是按物理数据页,因此您可以按任意顺序获得结果——在某种程度上,可能仍按插入顺序,也可能不按插入顺序。
    猜你喜欢
    • 2015-01-25
    • 2015-01-27
    • 1970-01-01
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-10
    • 1970-01-01
    相关资源
    最近更新 更多