]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Remove HeapBitmapScan's skip_fetch optimization
authorAndres Freund <andres@anarazel.de>
Wed, 2 Apr 2025 18:25:17 +0000 (14:25 -0400)
committerAndres Freund <andres@anarazel.de>
Wed, 2 Apr 2025 18:42:03 +0000 (14:42 -0400)
The optimization does not take the removal of TIDs by a concurrent vacuum into
account. The concurrent vacuum can remove dead TIDs and make pages ALL_VISIBLE
while those dead TIDs are referenced in the bitmap. This can lead to a
skip_fetch scan returning too many tuples.

It likely would be possible to implement this optimization safely, but we
don't have the necessary infrastructure in place. Nor is it clear that it's
worth building that infrastructure, given how limited the skip_fetch
optimization is.

In the backbranches we just disable the optimization by always passing
need_tuples=true to table_beginscan_bm(). We can't perform API/ABI changes in
the backbranches and we want to make the change as minimal as possible.

Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reported-By: Konstantin Knizhnik <knizhnik@garret.ru>
Discussion: https://postgr.es/m/CAEze2Wg3gXXZTr6_rwC+s4-o2ZVFB5F985uUSgJTsECx6AmGcQ@mail.gmail.com
Backpatch-through: 13

src/backend/executor/nodeBitmapHeapscan.c

index 6b48a6d8350fb09e5ef70341ecbd6c8de9066e49..3d26d96cadd71437e96a652133e0ddc315f87ce8 100644 (file)
@@ -185,8 +185,21 @@ BitmapHeapNext(BitmapHeapScanState *node)
                 */
                if (!scan)
                {
-                       bool            need_tuples = false;
+                       bool            need_tuples = true;
 
+                       /*
+                        * Unfortunately it turns out that the below optimization does not
+                        * take the removal of TIDs by a concurrent vacuum into
+                        * account. The concurrent vacuum can remove dead TIDs and make
+                        * pages ALL_VISIBLE while those dead TIDs are referenced in the
+                        * bitmap. This would lead to a !need_tuples scan returning too
+                        * many tuples.
+                        *
+                        * In the back-branches, we therefore simply disable the
+                        * optimization. Removing all the relevant code would be too
+                        * invasive (and a major backpatching pain).
+                        */
+#ifdef NOT_ANYMORE
                        /*
                         * We can potentially skip fetching heap pages if we do not need
                         * any columns of the table, either for checking non-indexable
@@ -197,6 +210,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
                         */
                        need_tuples = (node->ss.ps.plan->qual != NIL ||
                                                   node->ss.ps.plan->targetlist != NIL);
+#endif
 
                        scan = table_beginscan_bm(node->ss.ss_currentRelation,
                                                                          node->ss.ps.state->es_snapshot,