From 2c03dbd19ea485cccf8e0ec348a5710e196a3d7c Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 21 Apr 2021 07:31:25 +0530
Subject: [PATCH v1] Skip VACUUM/ANALYZE of repeated relations

Skip vacuuming/analyzing of repeated relations to avoid
unnecessary processing. We do this only when no explicit
columns are specified, for instance, "VACUUM/ANALYZE foo,
foo;". When columns are specified along with relations
i.e. "VACUUM/ANALYZE foo(col1), foo(col2);", we don't want
to further optimize the cases when col1 = col2.
---
 src/backend/commands/vacuum.c        | 20 +++++++++++++++++++-
 src/test/regress/expected/vacuum.out |  2 +-
 src/test/regress/sql/vacuum.sql      |  2 +-
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 39df05c735..09d7971b15 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -438,6 +438,7 @@ vacuum(List *relations, VacuumParams *params,
 	PG_TRY();
 	{
 		ListCell   *cur;
+		List	*relids = NULL;
 
 		in_vacuum = true;
 		VacuumCostActive = (VacuumCostDelay > 0);
@@ -456,6 +457,16 @@ vacuum(List *relations, VacuumParams *params,
 		{
 			VacuumRelation *vrel = lfirst_node(VacuumRelation, cur);
 
+			/*
+			 * Skip VACUUM/ANALYZE of repeated relations. We do this only when
+			 * no explicit columns are specified, for instance, "VACUUM/ANALYZE
+			 * foo, foo;". When columns are specified along with relations
+			 * i.e. "VACUUM/ANALYZE foo(col1), foo(col2);", we don't want to
+			 * further optimize the cases when col1 = col2.
+			 */
+			if (vrel->va_cols == NULL && list_member_oid(relids, vrel->oid))
+				continue;
+
 			if (params->options & VACOPT_VACUUM)
 			{
 				if (!vacuum_rel(vrel->oid, vrel->relation, params))
@@ -488,11 +499,18 @@ vacuum(List *relations, VacuumParams *params,
 					/*
 					 * If we're not using separate xacts, better separate the
 					 * ANALYZE actions with CCIs.  This avoids trouble if user
-					 * says "ANALYZE t, t".
+					 * says "ANALYZE t(col1), t(col2)".
 					 */
 					CommandCounterIncrement();
 				}
 			}
+
+			/*
+			 * Remember the VACUUMed/ANALYZEed relation only when no explicit
+			 * columns are specified.
+			 */
+			if (vrel->va_cols == NULL)
+				relids = lappend_oid(relids, vrel->oid);
 		}
 	}
 	PG_FINALLY();
diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out
index 90cea6caa8..a67c56371d 100644
--- a/src/test/regress/expected/vacuum.out
+++ b/src/test/regress/expected/vacuum.out
@@ -218,7 +218,7 @@ ANALYZE vactst (i), vacparted (does_not_exist);
 ERROR:  column "does_not_exist" of relation "vacparted" does not exist
 ANALYZE vactst, vactst;
 BEGIN;  -- ANALYZE behaves differently inside a transaction block
-ANALYZE vactst, vactst;
+ANALYZE vactst (i), vactst (i);
 COMMIT;
 -- parenthesized syntax for ANALYZE
 ANALYZE (VERBOSE) does_not_exist;
diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql
index 93fd258fc0..7daa3a7723 100644
--- a/src/test/regress/sql/vacuum.sql
+++ b/src/test/regress/sql/vacuum.sql
@@ -183,7 +183,7 @@ ANALYZE vactst, does_not_exist, vacparted;
 ANALYZE vactst (i), vacparted (does_not_exist);
 ANALYZE vactst, vactst;
 BEGIN;  -- ANALYZE behaves differently inside a transaction block
-ANALYZE vactst, vactst;
+ANALYZE vactst (i), vactst (i);
 COMMIT;
 
 -- parenthesized syntax for ANALYZE
-- 
2.25.1

