diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 477982d..b907f72 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -114,6 +114,7 @@ int			max_prepared_xacts = 0;
 typedef struct GlobalTransactionData
 {
 	PGPROC		proc;			/* dummy proc */
+	PGPROC_MINIMAL proc_minimal;	/* dummy proc_minimal */
 	BackendId	dummyBackendId; /* similar to backend id for backends */
 	TimestampTz prepared_at;	/* time of preparation */
 	XLogRecPtr	prepare_lsn;	/* XLOG offset of prepare record */
@@ -223,6 +224,9 @@ TwoPhaseShmemInit(void)
 			 * technique.
 			 */
 			gxacts[i].dummyBackendId = MaxBackends + 1 + i;
+
+			/* Initialize minimal proc structure from the global structure */
+			gxacts[i].proc.proc_minimal = &gxacts[i].proc_minimal;
 		}
 	}
 	else
@@ -310,14 +314,15 @@ MarkAsPreparing(TransactionId xid, const char *gid,
 	gxact->proc.waitStatus = STATUS_OK;
 	/* We set up the gxact's VXID as InvalidBackendId/XID */
 	gxact->proc.lxid = (LocalTransactionId) xid;
-	gxact->proc.xid = xid;
-	gxact->proc.xmin = InvalidTransactionId;
+	gxact->proc.proc_minimal = &gxact->proc_minimal;
+	gxact->proc.proc_minimal->xid = xid;
+	gxact->proc.proc_minimal->xmin = InvalidTransactionId;
 	gxact->proc.pid = 0;
 	gxact->proc.backendId = InvalidBackendId;
 	gxact->proc.databaseId = databaseid;
 	gxact->proc.roleId = owner;
-	gxact->proc.inCommit = false;
-	gxact->proc.vacuumFlags = 0;
+	gxact->proc.proc_minimal->inCommit = false;
+	gxact->proc.proc_minimal->vacuumFlags = 0;
 	gxact->proc.lwWaiting = false;
 	gxact->proc.lwExclusive = false;
 	gxact->proc.lwWaitLink = NULL;
@@ -326,8 +331,8 @@ MarkAsPreparing(TransactionId xid, const char *gid,
 	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
 		SHMQueueInit(&(gxact->proc.myProcLocks[i]));
 	/* subxid data must be filled later by GXactLoadSubxactData */
-	gxact->proc.subxids.overflowed = false;
-	gxact->proc.subxids.nxids = 0;
+	gxact->proc.proc_minimal->overflowed = false;
+	gxact->proc.proc_minimal->nxids = 0;
 
 	gxact->prepared_at = prepared_at;
 	/* initialize LSN to 0 (start of WAL) */
@@ -361,14 +366,14 @@ GXactLoadSubxactData(GlobalTransaction gxact, int nsubxacts,
 	/* We need no extra lock since the GXACT isn't valid yet */
 	if (nsubxacts > PGPROC_MAX_CACHED_SUBXIDS)
 	{
-		gxact->proc.subxids.overflowed = true;
+		gxact->proc.proc_minimal->overflowed = true;
 		nsubxacts = PGPROC_MAX_CACHED_SUBXIDS;
 	}
 	if (nsubxacts > 0)
 	{
 		memcpy(gxact->proc.subxids.xids, children,
 			   nsubxacts * sizeof(TransactionId));
-		gxact->proc.subxids.nxids = nsubxacts;
+		gxact->proc.proc_minimal->nxids = nsubxacts;
 	}
 }
 
@@ -519,7 +524,7 @@ TransactionIdIsPrepared(TransactionId xid)
 	{
 		GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
 
-		if (gxact->valid && gxact->proc.xid == xid)
+		if (gxact->valid && gxact->proc_minimal.xid == xid)
 		{
 			result = true;
 			break;
@@ -656,7 +661,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		MemSet(values, 0, sizeof(values));
 		MemSet(nulls, 0, sizeof(nulls));
 
-		values[0] = TransactionIdGetDatum(gxact->proc.xid);
+		values[0] = TransactionIdGetDatum(gxact->proc_minimal.xid);
 		values[1] = CStringGetTextDatum(gxact->gid);
 		values[2] = TimestampTzGetDatum(gxact->prepared_at);
 		values[3] = ObjectIdGetDatum(gxact->owner);
@@ -712,7 +717,7 @@ TwoPhaseGetDummyProc(TransactionId xid)
 	{
 		GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
 
-		if (gxact->proc.xid == xid)
+		if (gxact->proc_minimal.xid == xid)
 		{
 			result = &gxact->proc;
 			break;
@@ -841,7 +846,7 @@ save_state_data(const void *data, uint32 len)
 void
 StartPrepare(GlobalTransaction gxact)
 {
-	TransactionId xid = gxact->proc.xid;
+	TransactionId xid = gxact->proc_minimal.xid;
 	TwoPhaseFileHeader hdr;
 	TransactionId *children;
 	RelFileNode *commitrels;
@@ -913,7 +918,7 @@ StartPrepare(GlobalTransaction gxact)
 void
 EndPrepare(GlobalTransaction gxact)
 {
-	TransactionId xid = gxact->proc.xid;
+	TransactionId xid = gxact->proc_minimal.xid;
 	TwoPhaseFileHeader *hdr;
 	char		path[MAXPGPATH];
 	XLogRecData *record;
@@ -1021,7 +1026,7 @@ EndPrepare(GlobalTransaction gxact)
 	 */
 	START_CRIT_SECTION();
 
-	MyProc->inCommit = true;
+	MyProc->proc_minimal->inCommit = true;
 
 	gxact->prepare_lsn = XLogInsert(RM_XACT_ID, XLOG_XACT_PREPARE,
 									records.head);
@@ -1069,7 +1074,7 @@ EndPrepare(GlobalTransaction gxact)
 	 * checkpoint starting after this will certainly see the gxact as a
 	 * candidate for fsyncing.
 	 */
-	MyProc->inCommit = false;
+	MyProc->proc_minimal->inCommit = false;
 
 	END_CRIT_SECTION();
 
@@ -1260,7 +1265,7 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
 	 * try to commit the same GID at once.
 	 */
 	gxact = LockGXact(gid, GetUserId());
-	xid = gxact->proc.xid;
+	xid = gxact->proc_minimal.xid;
 
 	/*
 	 * Read and validate the state file
@@ -1543,7 +1548,7 @@ CheckPointTwoPhase(XLogRecPtr redo_horizon)
 
 		if (gxact->valid &&
 			XLByteLE(gxact->prepare_lsn, redo_horizon))
-			xids[nxids++] = gxact->proc.xid;
+			xids[nxids++] = gxact->proc_minimal.xid;
 	}
 
 	LWLockRelease(TwoPhaseStateLock);
@@ -1972,7 +1977,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
 	START_CRIT_SECTION();
 
 	/* See notes in RecordTransactionCommit */
-	MyProc->inCommit = true;
+	MyProc->proc_minimal->inCommit = true;
 
 	/* Emit the XLOG commit record */
 	xlrec.xid = xid;
@@ -2037,7 +2042,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
 	TransactionIdCommitTree(xid, nchildren, children);
 
 	/* Checkpoint can proceed now */
-	MyProc->inCommit = false;
+	MyProc->proc_minimal->inCommit = false;
 
 	END_CRIT_SECTION();
 
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 61dcfed..0effa1a 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -54,7 +54,7 @@ GetNewTransactionId(bool isSubXact)
 	if (IsBootstrapProcessingMode())
 	{
 		Assert(!isSubXact);
-		MyProc->xid = BootstrapTransactionId;
+		MyProc->proc_minimal->xid = BootstrapTransactionId;
 		return BootstrapTransactionId;
 	}
 
@@ -210,18 +210,18 @@ GetNewTransactionId(bool isSubXact)
 		volatile PGPROC *myproc = MyProc;
 
 		if (!isSubXact)
-			myproc->xid = xid;
+			myproc->proc_minimal->xid = xid;
 		else
 		{
-			int			nxids = myproc->subxids.nxids;
+			int			nxids = myproc->proc_minimal->nxids;
 
 			if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
 			{
 				myproc->subxids.xids[nxids] = xid;
-				myproc->subxids.nxids = nxids + 1;
+				myproc->proc_minimal->nxids = nxids + 1;
 			}
 			else
-				myproc->subxids.overflowed = true;
+				myproc->proc_minimal->overflowed = true;
 		}
 	}
 
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index c151d3b..838bd23 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -981,7 +981,7 @@ RecordTransactionCommit(void)
 		 * bit fuzzy, but it doesn't matter.
 		 */
 		START_CRIT_SECTION();
-		MyProc->inCommit = true;
+		MyProc->proc_minimal->inCommit = true;
 
 		SetCurrentTransactionStopTimestamp();
 
@@ -1155,7 +1155,7 @@ RecordTransactionCommit(void)
 	 */
 	if (markXidCommitted)
 	{
-		MyProc->inCommit = false;
+		MyProc->proc_minimal->inCommit = false;
 		END_CRIT_SECTION();
 	}
 
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 32985a4..a6ee452 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -223,7 +223,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
 	 * OK, let's do it.  First let other backends know I'm in ANALYZE.
 	 */
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-	MyProc->vacuumFlags |= PROC_IN_ANALYZE;
+	MyProc->proc_minimal->vacuumFlags |= PROC_IN_ANALYZE;
 	LWLockRelease(ProcArrayLock);
 
 	/*
@@ -250,7 +250,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
 	 * because the vacuum flag is cleared by the end-of-xact code.
 	 */
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-	MyProc->vacuumFlags &= ~PROC_IN_ANALYZE;
+	MyProc->proc_minimal->vacuumFlags &= ~PROC_IN_ANALYZE;
 	LWLockRelease(ProcArrayLock);
 }
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index f42504c..c85c002 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -893,9 +893,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 		 * which is probably Not Good.
 		 */
 		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-		MyProc->vacuumFlags |= PROC_IN_VACUUM;
+		MyProc->proc_minimal->vacuumFlags |= PROC_IN_VACUUM;
 		if (for_wraparound)
-			MyProc->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
+			MyProc->proc_minimal->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
 		LWLockRelease(ProcArrayLock);
 	}
 
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index dd2d6ee..aa54a98 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -702,7 +702,7 @@ ProcessStandbyHSFeedbackMessage(void)
 	 * safe, and if we're moving it backwards, well, the data is at risk
 	 * already since a VACUUM could have just finished calling GetOldestXmin.)
 	 */
-	MyProc->xmin = reply.xmin;
+	MyProc->proc_minimal->xmin = reply.xmin;
 }
 
 /* Main loop of walsender process */
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 1a48485..f0e1c5a 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -141,6 +141,29 @@ static void DisplayXidCache(void);
 #define xc_slow_answer_inc()		((void) 0)
 #endif   /* XIDCACHE_DEBUG */
 
+/*
+ * Get the PROC_MINIMAL structure corresponding to the given PGPROC. The trick
+ * is to avoid access to any PGPROC member to find the minimal structure
+ * because we want to avoid access to any PGPROC member unless its absolutely
+ * necessary. This reduces cache misses and faults. Except for dummy procs for
+ * prepared transactions, all other procs have a corresponding entry in the
+ * allProcs_Minimal array of PGPROC_MINIMAL. So we use pointer arithmetic to
+ * get that.
+ *
+ * XXX A branch mis-prediction can still end up touching the PGPROC
+ * proc_minimal member and that would cause cache miss. We have seen this on
+ * HP-UX compiler. It might be easier to handle with GCC by use of
+ * likely/unlikely hint knowing that in almost all cases its not needed to go
+ * to the PGPROC member or by rearranging the following code. For example, we
+ * can return (PGPROC_MINIMAL **) to avoid accessing PGPROC structure unless
+ * its required for prepared transaction
+ */
+#define PGProcGetMinimal(proc, procglobal) \
+		((proc) >= (procglobal)->allProcs && \
+		 (proc) < (procglobal)->allProcs + (procglobal)->allProcCount) ? \
+			&(procglobal)->allProcs_Minimal[(proc) - (procglobal)->allProcs] : \
+			(proc)->proc_minimal;
+
 /* Primitives for KnownAssignedXids array handling for standby */
 static void KnownAssignedXidsCompress(bool force);
 static void KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid,
@@ -253,6 +276,7 @@ void
 ProcArrayAdd(PGPROC *proc)
 {
 	ProcArrayStruct *arrayP = procArray;
+	int index;
 
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 
@@ -269,7 +293,28 @@ ProcArrayAdd(PGPROC *proc)
 				 errmsg("sorry, too many clients already")));
 	}
 
-	arrayP->procs[arrayP->numProcs] = proc;
+	/*
+	 * Keep the procs array sorted by (PGPROC *) so that we can utilize
+	 * locality of references much better. This is useful while traversing the
+	 * ProcArray because there is a increased likelyhood of finding the next
+	 * PGPROC structure in the cache.
+	 * 
+	 * Since the occurance of adding/removing a proc is much lower than the
+	 * access to the ProcArray itself, the overhead should be marginal
+	 */
+	for (index = 0; index < arrayP->numProcs; index++)
+	{
+		/*
+		 * If we are the first PGPROC or if we have found our right position in
+		 * the array, break
+		 */
+		if ((arrayP->procs[index] == NULL) || (arrayP->procs[index] > proc))
+			break;
+	}
+
+	memmove(&arrayP->procs[index + 1], &arrayP->procs[index],
+			(arrayP->numProcs - index) * sizeof (PGPROC *));
+	arrayP->procs[index] = proc;
 	arrayP->numProcs++;
 
 	LWLockRelease(ProcArrayLock);
@@ -318,7 +363,9 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
 	{
 		if (arrayP->procs[index] == proc)
 		{
-			arrayP->procs[index] = arrayP->procs[arrayP->numProcs - 1];
+			/* Keep the PGPROC array sorted. See notes above */
+			memmove(&arrayP->procs[index], &arrayP->procs[index + 1],
+					(arrayP->numProcs - index - 1) * sizeof (PGPROC *));
 			arrayP->procs[arrayP->numProcs - 1] = NULL; /* for debugging */
 			arrayP->numProcs--;
 			LWLockRelease(ProcArrayLock);
@@ -361,17 +408,17 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
 
 		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 
-		proc->xid = InvalidTransactionId;
+		proc->proc_minimal->xid = InvalidTransactionId;
 		proc->lxid = InvalidLocalTransactionId;
-		proc->xmin = InvalidTransactionId;
+		proc->proc_minimal->xmin = InvalidTransactionId;
 		/* must be cleared with xid/xmin: */
-		proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
-		proc->inCommit = false; /* be sure this is cleared in abort */
+		proc->proc_minimal->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+		proc->proc_minimal->inCommit = false; /* be sure this is cleared in abort */
 		proc->recoveryConflictPending = false;
 
 		/* Clear the subtransaction-XID cache too while holding the lock */
-		proc->subxids.nxids = 0;
-		proc->subxids.overflowed = false;
+		proc->proc_minimal->nxids = 0;
+		proc->proc_minimal->overflowed = false;
 
 		/* Also advance global latestCompletedXid while holding the lock */
 		if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
@@ -390,10 +437,10 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
 		Assert(!TransactionIdIsValid(proc->xid));
 
 		proc->lxid = InvalidLocalTransactionId;
-		proc->xmin = InvalidTransactionId;
+		proc->proc_minimal->xmin = InvalidTransactionId;
 		/* must be cleared with xid/xmin: */
-		proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
-		proc->inCommit = false; /* be sure this is cleared in abort */
+		proc->proc_minimal->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+		proc->proc_minimal->inCommit = false; /* be sure this is cleared in abort */
 		proc->recoveryConflictPending = false;
 
 		Assert(proc->subxids.nxids == 0);
@@ -419,18 +466,18 @@ ProcArrayClearTransaction(PGPROC *proc)
 	 * duplicate with the gxact that has already been inserted into the
 	 * ProcArray.
 	 */
-	proc->xid = InvalidTransactionId;
+	proc->proc_minimal->xid = InvalidTransactionId;
 	proc->lxid = InvalidLocalTransactionId;
-	proc->xmin = InvalidTransactionId;
+	proc->proc_minimal->xmin = InvalidTransactionId;
 	proc->recoveryConflictPending = false;
 
 	/* redundant, but just in case */
-	proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
-	proc->inCommit = false;
+	proc->proc_minimal->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+	proc->proc_minimal->inCommit = false;
 
 	/* Clear the subtransaction-XID cache too */
-	proc->subxids.nxids = 0;
-	proc->subxids.overflowed = false;
+	proc->proc_minimal->nxids = 0;
+	proc->proc_minimal->overflowed = false;
 }
 
 /*
@@ -741,6 +788,10 @@ TransactionIdIsInProgress(TransactionId xid)
 	TransactionId topxid;
 	int			i,
 				j;
+#ifdef NOT_USED	
+	static PGPROC **procs = NULL;
+	static PGPROC_MINIMAL *txns = NULL;
+#endif
 
 	/*
 	 * Don't bother checking a transaction older than RecentXmin; it could not
@@ -811,15 +862,19 @@ TransactionIdIsInProgress(TransactionId xid)
 	/* No shortcuts, gotta grovel through the array */
 	for (i = 0; i < arrayP->numProcs; i++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[i];
+		volatile PGPROC_MINIMAL *proc_minimal;
 		TransactionId pxid;
 
 		/* Ignore my own proc --- dealt with it above */
 		if (proc == MyProc)
 			continue;
 
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
+
 		/* Fetch xid just once - see GetNewTransactionId */
-		pxid = proc->xid;
+		pxid = proc_minimal->xid;
 
 		if (!TransactionIdIsValid(pxid))
 			continue;
@@ -844,7 +899,7 @@ TransactionIdIsInProgress(TransactionId xid)
 		/*
 		 * Step 2: check the cached child-Xids arrays
 		 */
-		for (j = proc->subxids.nxids - 1; j >= 0; j--)
+		for (j = proc_minimal->nxids - 1; j >= 0; j--)
 		{
 			/* Fetch xid just once - see GetNewTransactionId */
 			TransactionId cxid = proc->subxids.xids[j];
@@ -864,7 +919,7 @@ TransactionIdIsInProgress(TransactionId xid)
 		 * we hold ProcArrayLock.  So we can't miss an Xid that we need to
 		 * worry about.)
 		 */
-		if (proc->subxids.overflowed)
+		if (proc_minimal->overflowed)
 			xids[nxids++] = pxid;
 	}
 
@@ -965,10 +1020,15 @@ TransactionIdIsActive(TransactionId xid)
 
 	for (i = 0; i < arrayP->numProcs; i++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[i];
+		volatile PGPROC_MINIMAL *proc_minimal;
+		TransactionId pxid;
+
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
 
 		/* Fetch xid just once - see GetNewTransactionId */
-		TransactionId pxid = proc->xid;
+		pxid = proc_minimal->xid;
 
 		if (!TransactionIdIsValid(pxid))
 			continue;
@@ -1060,9 +1120,13 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
+	   
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
 
-		if (ignoreVacuum && (proc->vacuumFlags & PROC_IN_VACUUM))
+		if (ignoreVacuum && (proc_minimal->vacuumFlags & PROC_IN_VACUUM))
 			continue;
 
 		if (allDbs ||
@@ -1070,7 +1134,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
 			proc->databaseId == 0)		/* always include WalSender */
 		{
 			/* Fetch xid just once - see GetNewTransactionId */
-			TransactionId xid = proc->xid;
+			TransactionId xid = proc_minimal->xid;
 
 			/* First consider the transaction's own Xid, if any */
 			if (TransactionIdIsNormal(xid) &&
@@ -1084,7 +1148,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
 			 * have an Xmin but not (yet) an Xid; conversely, if it has an
 			 * Xid, that could determine some not-yet-set Xmin.
 			 */
-			xid = proc->xmin;	/* Fetch just once */
+			xid = proc_minimal->xmin;	/* Fetch just once */
 			if (TransactionIdIsNormal(xid) &&
 				TransactionIdPrecedes(xid, result))
 				result = xid;
@@ -1271,21 +1335,35 @@ GetSnapshotData(Snapshot snapshot)
 		 */
 		for (index = 0; index < arrayP->numProcs; index++)
 		{
+			volatile PROC_HDR *procglobal = ProcGlobal;
 			volatile PGPROC *proc = arrayP->procs[index];
+			volatile PGPROC_MINIMAL *proc_minimal;
 			TransactionId xid;
 
+			/*
+			 * All the information needed by GetSnapshotData is stored out of
+			 * band as an array of PGPROC_MINIMAL structures. The only exception
+			 * is the dummy PGPROC for prepared transaction.
+			 *
+			 * We try to avoid accessing any field from the PGPROC because that
+			 * may cause cache miss and associated overhead. We instead try to
+			 * directly access the relevant information by doing pointer
+			 * arithmatic.
+			 */
+			proc_minimal = PGProcGetMinimal(proc, procglobal);
+
 			/* Ignore procs running LAZY VACUUM */
-			if (proc->vacuumFlags & PROC_IN_VACUUM)
+			if (proc_minimal->vacuumFlags & PROC_IN_VACUUM)
 				continue;
 
 			/* Update globalxmin to be the smallest valid xmin */
-			xid = proc->xmin;	/* fetch just once */
+			xid = proc_minimal->xmin;	/* fetch just once */
 			if (TransactionIdIsNormal(xid) &&
 				TransactionIdPrecedes(xid, globalxmin))
 				globalxmin = xid;
 
 			/* Fetch xid just once - see GetNewTransactionId */
-			xid = proc->xid;
+			xid = proc_minimal->xid;
 
 			/*
 			 * If the transaction has been assigned an xid < xmax we add it to
@@ -1323,11 +1401,11 @@ GetSnapshotData(Snapshot snapshot)
 			 */
 			if (!suboverflowed && proc != MyProc)
 			{
-				if (proc->subxids.overflowed)
+				if (proc_minimal->overflowed)
 					suboverflowed = true;
 				else
 				{
-					int			nxids = proc->subxids.nxids;
+					int			nxids = proc_minimal->nxids;
 
 					if (nxids > 0)
 					{
@@ -1372,9 +1450,8 @@ GetSnapshotData(Snapshot snapshot)
 			suboverflowed = true;
 	}
 
-	if (!TransactionIdIsValid(MyProc->xmin))
-		MyProc->xmin = TransactionXmin = xmin;
-
+	if (!TransactionIdIsValid(MyProc->proc_minimal->xmin))
+		MyProc->proc_minimal->xmin = TransactionXmin = xmin;
 	LWLockRelease(ProcArrayLock);
 
 	/*
@@ -1436,14 +1513,18 @@ ProcArrayInstallImportedXmin(TransactionId xmin, TransactionId sourcexid)
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
 		TransactionId xid;
 
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
+
 		/* Ignore procs running LAZY VACUUM */
-		if (proc->vacuumFlags & PROC_IN_VACUUM)
+		if (proc_minimal->vacuumFlags & PROC_IN_VACUUM)
 			continue;
 
-		xid = proc->xid;	/* fetch just once */
+		xid = proc_minimal->xid;	/* fetch just once */
 		if (xid != sourcexid)
 			continue;
 
@@ -1459,7 +1540,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin, TransactionId sourcexid)
 		/*
 		 * Likewise, let's just make real sure its xmin does cover us.
 		 */
-		xid = proc->xmin;	/* fetch just once */
+		xid = proc_minimal->xmin;	/* fetch just once */
 		if (!TransactionIdIsNormal(xid) ||
 			!TransactionIdPrecedesOrEquals(xid, xmin))
 			continue;
@@ -1470,7 +1551,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin, TransactionId sourcexid)
 		 * GetSnapshotData first, we'll be overwriting a valid xmin here,
 		 * so we don't check that.)
 		 */
-		MyProc->xmin = TransactionXmin = xmin;
+		MyProc->proc_minimal->xmin = TransactionXmin = xmin;
 
 		result = true;
 		break;
@@ -1562,12 +1643,16 @@ GetRunningTransactionData(void)
 	 */
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
 		TransactionId xid;
 		int			nxids;
 
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
+
 		/* Fetch xid just once - see GetNewTransactionId */
-		xid = proc->xid;
+		xid = proc_minimal->xid;
 
 		/*
 		 * We don't need to store transactions that don't have a TransactionId
@@ -1585,7 +1670,7 @@ GetRunningTransactionData(void)
 		 * Save subtransaction XIDs. Other backends can't add or remove
 		 * entries while we're holding XidGenLock.
 		 */
-		nxids = proc->subxids.nxids;
+		nxids = proc_minimal->nxids;
 		if (nxids > 0)
 		{
 			memcpy(&xids[count], (void *) proc->subxids.xids,
@@ -1593,7 +1678,7 @@ GetRunningTransactionData(void)
 			count += nxids;
 			subcount += nxids;
 
-			if (proc->subxids.overflowed)
+			if (proc_minimal->overflowed)
 				suboverflowed = true;
 
 			/*
@@ -1653,11 +1738,15 @@ GetOldestActiveTransactionId(void)
 	 */
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
 		TransactionId xid;
 
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
+
 		/* Fetch xid just once - see GetNewTransactionId */
-		xid = proc->xid;
+		xid = proc_minimal->xid;
 
 		if (!TransactionIdIsNormal(xid))
 			continue;
@@ -1709,12 +1798,17 @@ GetTransactionsInCommit(TransactionId **xids_p)
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
+		TransactionId pxid;
+
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
 
 		/* Fetch xid just once - see GetNewTransactionId */
-		TransactionId pxid = proc->xid;
+		pxid = proc_minimal->xid;
 
-		if (proc->inCommit && TransactionIdIsValid(pxid))
+		if (proc_minimal->inCommit && TransactionIdIsValid(pxid))
 			xids[nxids++] = pxid;
 	}
 
@@ -1744,12 +1838,17 @@ HaveTransactionsInCommit(TransactionId *xids, int nxids)
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
+		TransactionId pxid;
+
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
 
 		/* Fetch xid just once - see GetNewTransactionId */
-		TransactionId pxid = proc->xid;
+		pxid = proc_minimal->xid;
 
-		if (proc->inCommit && TransactionIdIsValid(pxid))
+		if (proc_minimal->inCommit && TransactionIdIsValid(pxid))
 		{
 			int			i;
 
@@ -1833,9 +1932,13 @@ BackendXidGetPid(TransactionId xid)
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
 
-		if (proc->xid == xid)
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
+
+		if (proc_minimal->xid == xid)
 		{
 			result = proc->pid;
 			break;
@@ -1906,13 +2009,13 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
 		if (proc == MyProc)
 			continue;
 
-		if (excludeVacuum & proc->vacuumFlags)
+		if (excludeVacuum & proc->proc_minimal->vacuumFlags)
 			continue;
 
 		if (allDbs || proc->databaseId == MyDatabaseId)
 		{
 			/* Fetch xmin just once - might change on us */
-			TransactionId pxmin = proc->xmin;
+			TransactionId pxmin = proc->proc_minimal->xmin;
 
 			if (excludeXmin0 && !TransactionIdIsValid(pxmin))
 				continue;
@@ -2006,7 +2109,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
 			proc->databaseId == dbOid)
 		{
 			/* Fetch xmin just once - can't change on us, but good coding */
-			TransactionId pxmin = proc->xmin;
+			TransactionId pxmin = proc->proc_minimal->xmin;
 
 			/*
 			 * We ignore an invalid pxmin because this means that backend has
@@ -2104,7 +2207,9 @@ MinimumActiveBackends(int min)
 	 */
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
+		volatile PROC_HDR *procglobal = ProcGlobal;
 		volatile PGPROC *proc = arrayP->procs[index];
+		volatile PGPROC_MINIMAL *proc_minimal;
 
 		/*
 		 * Since we're not holding a lock, need to check that the pointer is
@@ -2120,12 +2225,14 @@ MinimumActiveBackends(int min)
 		if (proc == NULL)
 			continue;
 
+		proc_minimal = PGProcGetMinimal(proc, procglobal);
+
 		if (proc == MyProc)
 			continue;			/* do not count myself */
+		if (proc_minimal->xid == InvalidTransactionId)
+			continue;			/* do not count if no XID assigned */
 		if (proc->pid == 0)
 			continue;			/* do not count prepared xacts */
-		if (proc->xid == InvalidTransactionId)
-			continue;			/* do not count if no XID assigned */
 		if (proc->waitLock != NULL)
 			continue;			/* do not count if blocked on a lock */
 		count++;
@@ -2291,7 +2398,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
 			else
 			{
 				(*nbackends)++;
-				if ((proc->vacuumFlags & PROC_IS_AUTOVACUUM) &&
+				if ((proc->proc_minimal->vacuumFlags & PROC_IS_AUTOVACUUM) &&
 					nautovacs < MAXAUTOVACPIDS)
 					autovac_pids[nautovacs++] = proc->pid;
 			}
@@ -2321,8 +2428,8 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
 
 #define XidCacheRemove(i) \
 	do { \
-		MyProc->subxids.xids[i] = MyProc->subxids.xids[MyProc->subxids.nxids - 1]; \
-		MyProc->subxids.nxids--; \
+		MyProc->subxids.xids[i] = MyProc->subxids.xids[MyProc->proc_minimal->nxids - 1]; \
+		MyProc->proc_minimal->nxids--; \
 	} while (0)
 
 /*
@@ -2361,7 +2468,7 @@ XidCacheRemoveRunningXids(TransactionId xid,
 	{
 		TransactionId anxid = xids[i];
 
-		for (j = MyProc->subxids.nxids - 1; j >= 0; j--)
+		for (j = MyProc->proc_minimal->nxids - 1; j >= 0; j--)
 		{
 			if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
 			{
@@ -2377,11 +2484,11 @@ XidCacheRemoveRunningXids(TransactionId xid,
 		 * error during AbortSubTransaction.  So instead of Assert, emit a
 		 * debug warning.
 		 */
-		if (j < 0 && !MyProc->subxids.overflowed)
+		if (j < 0 && !MyProc->proc_minimal->overflowed)
 			elog(WARNING, "did not find subXID %u in MyProc", anxid);
 	}
 
-	for (j = MyProc->subxids.nxids - 1; j >= 0; j--)
+	for (j = MyProc->proc_minimal->nxids - 1; j >= 0; j--)
 	{
 		if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
 		{
@@ -2390,7 +2497,7 @@ XidCacheRemoveRunningXids(TransactionId xid,
 		}
 	}
 	/* Ordinarily we should have found it, unless the cache has overflowed */
-	if (j < 0 && !MyProc->subxids.overflowed)
+	if (j < 0 && !MyProc->proc_minimal->overflowed)
 		elog(WARNING, "did not find subXID %u in MyProc", xid);
 
 	/* Also advance global latestCompletedXid while holding the lock */
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index 7e7f6af..bb1e654 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -541,7 +541,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
 					 * vacuumFlag bit), but we don't do that here to avoid
 					 * grabbing ProcArrayLock.
 					 */
-					if (proc->vacuumFlags & PROC_IS_AUTOVACUUM)
+					if (proc->proc_minimal->vacuumFlags & PROC_IS_AUTOVACUUM)
 						blocking_autovacuum_proc = proc;
 
 					/* This proc hard-blocks checkProc */
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index ed8344f..3e7a557 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -3184,7 +3184,7 @@ GetRunningTransactionLocks(int *nlocks)
 			PGPROC	   *proc = proclock->tag.myProc;
 			LOCK	   *lock = proclock->tag.myLock;
 
-			accessExclusiveLocks[index].xid = proc->xid;
+			accessExclusiveLocks[index].xid = proc->proc_minimal->xid;
 			accessExclusiveLocks[index].dbOid = lock->tag.locktag_field1;
 			accessExclusiveLocks[index].relOid = lock->tag.locktag_field2;
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index eda3a98..0261de7 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -113,6 +113,9 @@ ProcGlobalShmemSize(void)
 	/* ProcStructLock */
 	size = add_size(size, sizeof(slock_t));
 
+	size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGPROC_MINIMAL)));
+	size = add_size(size, mul_size(MaxBackends, sizeof(PGPROC_MINIMAL)));
+
 	return size;
 }
 
@@ -157,6 +160,7 @@ void
 InitProcGlobal(void)
 {
 	PGPROC	   *procs;
+	PGPROC_MINIMAL *procs_minimal;
 	int			i,
 				j;
 	bool		found;
@@ -195,6 +199,22 @@ InitProcGlobal(void)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
+
+	/*
+	 * Also allocate a separate array of PROC_MINIMAL structures. We keep this
+	 * out of band of the main PGPROC array to ensure the very heavily accessed
+	 * members of the PGPROC structure are stored contiguously in the memory.
+	 * This provides significant performance benefits, especially on a
+	 * multiprocessor system by improving cache hit ratio.
+	 *
+	 * Note: We separate the members needed by GetSnapshotData since that's the
+	 * most frequently accessed code path. There is one PROC_MINIMAL structure
+	 * for every PGPROC structure.
+	 */
+	procs_minimal = (PGPROC_MINIMAL *) ShmemAlloc(TotalProcs * sizeof(PGPROC_MINIMAL));
+	MemSet(procs_minimal, 0, TotalProcs * sizeof(PGPROC_MINIMAL));
+	ProcGlobal->allProcs_Minimal = procs_minimal;
+
 	for (i = 0; i < TotalProcs; i++)
 	{
 		/* Common initialization for all PGPROCs, regardless of type. */
@@ -203,6 +223,7 @@ InitProcGlobal(void)
 		PGSemaphoreCreate(&(procs[i].sem));
 		InitSharedLatch(&(procs[i].procLatch));
 		procs[i].backendLock = LWLockAssign();
+		procs[i].proc_minimal = &procs_minimal[i];
 
 		/*
 		 * Newly created PGPROCs for normal backends or for autovacuum must
@@ -313,18 +334,18 @@ InitProcess(void)
 	SHMQueueElemInit(&(MyProc->links));
 	MyProc->waitStatus = STATUS_OK;
 	MyProc->lxid = InvalidLocalTransactionId;
-	MyProc->xid = InvalidTransactionId;
-	MyProc->xmin = InvalidTransactionId;
+	MyProc->proc_minimal->xid = InvalidTransactionId;
+	MyProc->proc_minimal->xmin = InvalidTransactionId;
 	MyProc->pid = MyProcPid;
 	/* backendId, databaseId and roleId will be filled in later */
 	MyProc->backendId = InvalidBackendId;
 	MyProc->databaseId = InvalidOid;
 	MyProc->roleId = InvalidOid;
-	MyProc->inCommit = false;
-	MyProc->vacuumFlags = 0;
+	MyProc->proc_minimal->inCommit = false;
+	MyProc->proc_minimal->vacuumFlags = 0;
 	/* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
 	if (IsAutoVacuumWorkerProcess())
-		MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
+		MyProc->proc_minimal->vacuumFlags |= PROC_IS_AUTOVACUUM;
 	MyProc->lwWaiting = false;
 	MyProc->lwExclusive = false;
 	MyProc->lwWaitLink = NULL;
@@ -472,13 +493,13 @@ InitAuxiliaryProcess(void)
 	SHMQueueElemInit(&(MyProc->links));
 	MyProc->waitStatus = STATUS_OK;
 	MyProc->lxid = InvalidLocalTransactionId;
-	MyProc->xid = InvalidTransactionId;
-	MyProc->xmin = InvalidTransactionId;
+	MyProc->proc_minimal->xid = InvalidTransactionId;
+	MyProc->proc_minimal->xmin = InvalidTransactionId;
 	MyProc->backendId = InvalidBackendId;
 	MyProc->databaseId = InvalidOid;
 	MyProc->roleId = InvalidOid;
-	MyProc->inCommit = false;
-	MyProc->vacuumFlags = 0;
+	MyProc->proc_minimal->inCommit = false;
+	MyProc->proc_minimal->vacuumFlags = 0;
 	MyProc->lwWaiting = false;
 	MyProc->lwExclusive = false;
 	MyProc->lwWaitLink = NULL;
@@ -1053,8 +1074,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 			 * wraparound.
 			 */
 			if ((autovac != NULL) &&
-				(autovac->vacuumFlags & PROC_IS_AUTOVACUUM) &&
-				!(autovac->vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
+				(autovac->proc_minimal->vacuumFlags & PROC_IS_AUTOVACUUM) &&
+				!(autovac->proc_minimal->vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
 			{
 				int			pid = autovac->pid;
 
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 50fb780..bcfe3f3 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -577,7 +577,7 @@ static void
 SnapshotResetXmin(void)
 {
 	if (RegisteredSnapshots == 0 && ActiveSnapshot == NULL)
-		MyProc->xmin = InvalidTransactionId;
+		MyProc->proc_minimal->xmin = InvalidTransactionId;
 }
 
 /*
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index bc746a3..093a56e 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -21,6 +21,7 @@
 
 /* struct PGPROC is declared in proc.h, but must forward-reference it */
 typedef struct PGPROC PGPROC;
+typedef struct PGPROC_MINIMAL PGPROC_MINIMAL;
 
 typedef struct PROC_QUEUE
 {
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 6e798b1..a136309 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -35,8 +35,6 @@
 
 struct XidCache
 {
-	bool		overflowed;
-	int			nxids;
 	TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS];
 };
 
@@ -57,6 +55,8 @@ struct XidCache
  */
 #define		FP_LOCK_SLOTS_PER_BACKEND 16
 
+struct PGPROC_MINIMAL;
+
 /*
  * Each backend has a PGPROC struct in shared memory.  There is also a list of
  * currently-unused PGPROC structs that will be reallocated to new backends.
@@ -87,14 +87,7 @@ struct PGPROC
 								 * being executed by this proc, if running;
 								 * else InvalidLocalTransactionId */
 
-	TransactionId xid;			/* id of top-level transaction currently being
-								 * executed by this proc, if running and XID
-								 * is assigned; else InvalidTransactionId */
-
-	TransactionId xmin;			/* minimal running XID as it was when we were
-								 * starting our xact, excluding LAZY VACUUM:
-								 * vacuum must not remove tuples deleted by
-								 * xid >= xmin ! */
+	PGPROC_MINIMAL	*proc_minimal;
 
 	int			pid;			/* Backend's process ID; 0 if prepared xact */
 
@@ -103,10 +96,6 @@ struct PGPROC
 	Oid			databaseId;		/* OID of database this backend is using */
 	Oid			roleId;			/* OID of role using this backend */
 
-	bool		inCommit;		/* true if within commit critical section */
-
-	uint8		vacuumFlags;	/* vacuum-related flags, see above */
-
 	/*
 	 * While in hot standby mode, shows that a conflict signal has been sent
 	 * for the current transaction. Set/cleared while holding ProcArrayLock,
@@ -161,6 +150,32 @@ struct PGPROC
 
 extern PGDLLIMPORT PGPROC *MyProc;
 
+/*
+ * A minimal part of the PGPROC. We store these members out of the main PGPROC
+ * structure since they are very heavily accessed members and usually in a loop
+ * for all active PGPROCs. Storing them in a separate array ensures that these
+ * members can be very effeciently accessed with minimum cache misses. On a
+ * large multiprocessor system, this can show a significant performance
+ * improvement.
+ */
+struct PGPROC_MINIMAL
+{
+	TransactionId xid;			/* id of top-level transaction currently being
+								 * executed by this proc, if running and XID
+								 * is assigned; else InvalidTransactionId */
+
+	TransactionId xmin;			/* minimal running XID as it was when we were
+								 * starting our xact, excluding LAZY VACUUM:
+								 * vacuum must not remove tuples deleted by
+								 * xid >= xmin ! */
+
+	uint8		vacuumFlags;	/* vacuum-related flags, see above */
+	bool		overflowed;
+	bool		inCommit;		/* true if within commit critical section */
+
+	int			nxids;
+};
+
 
 /*
  * There is one ProcGlobal struct for the whole database cluster.
@@ -169,6 +184,8 @@ typedef struct PROC_HDR
 {
 	/* Array of PGPROC structures (not including dummies for prepared txns) */
 	PGPROC	   *allProcs;
+	/* Array of PGPROC_MINIMAL structures (not including dummies for prepared txns */
+	PGPROC_MINIMAL	*allProcs_Minimal;
 	/* Length of allProcs array */
 	uint32		allProcCount;
 	/* Head of list of free PGPROC structures */
