public inbox for [email protected]  
help / color / mirror / Atom feed
From: Quan Zongliang <[email protected]>
To: pgsql-hackers <[email protected]>
Subject: Improving the heapgetpage function improves performance in common scenarios
Date: Thu, 24 Aug 2023 18:55:28 +0800
Message-ID: <[email protected]> (raw)

Hi

In the function heapgetpage. If a table is not updated very frequently. 
Many actions in tuple loops are superfluous. For all_visible pages, 
loctup does not need to be assigned, nor does the "valid" variable. 
CheckForSerializableConflictOutNeeded from 
HeapCheckForSerializableConflictOut function, it only need to inspect at 
the beginning of the cycle only once. Using vtune you can clearly see 
the result (attached heapgetpage.jpg).

So by splitting the loop logic into two parts, the vtune results show 
significant improvement (attached heapgetpage-allvis.jpg).

The test data uses TPC-H's table "orders" with a scale=20, 30 million rows.


Quan Zongliang
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7ed72abe59..21ac1da8ab 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -451,30 +451,43 @@ heapgetpage(TableScanDesc sscan, BlockNumber block)
 	 */
 	all_visible = PageIsAllVisible(page) && !snapshot->takenDuringRecovery;
 
-	for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
+	if (all_visible && !CheckForSerializableConflictOutNeeded(scan->rs_base.rs_rd, snapshot))
 	{
-		ItemId		lpp = PageGetItemId(page, lineoff);
-		HeapTupleData loctup;
-		bool		valid;
+		for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
+		{
+			if (!ItemIdIsNormal(PageGetItemId(page, lineoff)))
+				continue;
 
-		if (!ItemIdIsNormal(lpp))
-			continue;
+			scan->rs_vistuples[ntup++] = lineoff;
+		}
+	}
+	else
+	{
+		for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
+		{
+			ItemId		lpp = PageGetItemId(page, lineoff);
+			HeapTupleData loctup;
+			bool		valid;
 
-		loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
-		loctup.t_data = (HeapTupleHeader) PageGetItem(page, lpp);
-		loctup.t_len = ItemIdGetLength(lpp);
-		ItemPointerSet(&(loctup.t_self), block, lineoff);
+			if (!ItemIdIsNormal(lpp))
+				continue;
 
-		if (all_visible)
-			valid = true;
-		else
-			valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
+			loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
+			loctup.t_data = (HeapTupleHeader) PageGetItem(page, lpp);
+			loctup.t_len = ItemIdGetLength(lpp);
+			ItemPointerSet(&(loctup.t_self), block, lineoff);
+
+			if (all_visible)
+				valid = true;
+			else
+				valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
 
-		HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
-											&loctup, buffer, snapshot);
+			HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
+												&loctup, buffer, snapshot);
 
-		if (valid)
-			scan->rs_vistuples[ntup++] = lineoff;
+			if (valid)
+				scan->rs_vistuples[ntup++] = lineoff;
+		}
 	}
 
 	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);


Attachments:

  [image/jpeg] heapgetpage-allvis.jpg (43.0K, ../[email protected]/2-heapgetpage-allvis.jpg)
  download | view image

  [image/jpeg] heapgetpage.jpg (99.9K, ../[email protected]/3-heapgetpage.jpg)
  download | view image

  [text/plain] heapgetpage.patch (2.1K, ../[email protected]/4-heapgetpage.patch)
  download | inline diff:
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7ed72abe59..21ac1da8ab 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -451,30 +451,43 @@ heapgetpage(TableScanDesc sscan, BlockNumber block)
 	 */
 	all_visible = PageIsAllVisible(page) && !snapshot->takenDuringRecovery;
 
-	for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
+	if (all_visible && !CheckForSerializableConflictOutNeeded(scan->rs_base.rs_rd, snapshot))
 	{
-		ItemId		lpp = PageGetItemId(page, lineoff);
-		HeapTupleData loctup;
-		bool		valid;
+		for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
+		{
+			if (!ItemIdIsNormal(PageGetItemId(page, lineoff)))
+				continue;
 
-		if (!ItemIdIsNormal(lpp))
-			continue;
+			scan->rs_vistuples[ntup++] = lineoff;
+		}
+	}
+	else
+	{
+		for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
+		{
+			ItemId		lpp = PageGetItemId(page, lineoff);
+			HeapTupleData loctup;
+			bool		valid;
 
-		loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
-		loctup.t_data = (HeapTupleHeader) PageGetItem(page, lpp);
-		loctup.t_len = ItemIdGetLength(lpp);
-		ItemPointerSet(&(loctup.t_self), block, lineoff);
+			if (!ItemIdIsNormal(lpp))
+				continue;
 
-		if (all_visible)
-			valid = true;
-		else
-			valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
+			loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
+			loctup.t_data = (HeapTupleHeader) PageGetItem(page, lpp);
+			loctup.t_len = ItemIdGetLength(lpp);
+			ItemPointerSet(&(loctup.t_self), block, lineoff);
+
+			if (all_visible)
+				valid = true;
+			else
+				valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
 
-		HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
-											&loctup, buffer, snapshot);
+			HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
+												&loctup, buffer, snapshot);
 
-		if (valid)
-			scan->rs_vistuples[ntup++] = lineoff;
+			if (valid)
+				scan->rs_vistuples[ntup++] = lineoff;
+		}
 	}
 
 	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);


view thread (4+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected]
  Subject: Re: Improving the heapgetpage function improves performance in common scenarios
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox