*** a/src/backend/postmaster/autovacuum.c
--- b/src/backend/postmaster/autovacuum.c
***************
*** 1069,1074 **** db_comparator(const void *a, const void *b)
--- 1069,1120 ----
  }
  
  /*
+  * Are there any running workers in the given database?
+  */
+ static bool
+ db_has_running_workers(avl_dbase *db)
+ {
+ 	bool		hasworkers = false;
+ 	dlist_iter	iter;
+ 
+ 	/* Allow for a NULL avl_dbase entry */
+ 	if (!db)
+ 		return false;
+ 
+ 	LWLockAcquire(AutovacuumLock, LW_SHARED);
+ 	dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers)
+ 	{
+ 		WorkerInfo	worker = dlist_container(WorkerInfoData, wi_links, iter.cur);
+ 
+ 		if (worker->wi_dboid == db->adl_datid)
+ 		{
+ 			hasworkers = true;
+ 			break;
+ 		}
+ 	}
+ 	LWLockRelease(AutovacuumLock);
+ 
+ 	return hasworkers;
+ }
+ 
+ /*
+  * Was this database processed less than the given number of milliseconds ago?
+  */
+ static bool
+ db_was_recently_processed(avl_dbase *db, TimestampTz current_time, int ms)
+ {
+ 	/* Allow for a NULL avl_dbase entry */
+ 	if (!db)
+ 		return false;
+ 
+ 	if (!TimestampDifferenceExceeds(db->adl_next_worker, current_time, 0) &&
+ 		!TimestampDifferenceExceeds(current_time, db->adl_next_worker, ms))
+ 		return true;
+ 
+ 	return false;
+ }
+ 
+ /*
   * do_start_worker
   *
   * Bare-bones procedure for starting an autovacuum worker from the launcher.
***************
*** 1090,1096 **** do_start_worker(void)
  	bool		for_multi_wrap;
  	avw_dbase  *avdb;
  	TimestampTz current_time;
! 	bool		skipit = false;
  	Oid			retval = InvalidOid;
  	MemoryContext tmpcxt,
  				oldcxt;
--- 1136,1142 ----
  	bool		for_multi_wrap;
  	avw_dbase  *avdb;
  	TimestampTz current_time;
! 	bool		skipped = false;
  	Oid			retval = InvalidOid;
  	MemoryContext tmpcxt,
  				oldcxt;
***************
*** 1118,1124 **** do_start_worker(void)
  	/* use fresh stats */
  	autovac_refresh_stats();
  
! 	/* Get a list of databases */
  	dblist = get_database_list();
  
  	/*
--- 1164,1170 ----
  	/* use fresh stats */
  	autovac_refresh_stats();
  
! 	/* Get a list of databases in pg_database */
  	dblist = get_database_list();
  
  	/*
***************
*** 1128,1135 **** do_start_worker(void)
  	 */
  	recentXid = ReadNewTransactionId();
  	xidForceLimit = recentXid - autovacuum_freeze_max_age;
! 	/* ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves */
! 	/* this can cause the limit to go backwards by 3, but that's OK */
  	if (xidForceLimit < FirstNormalTransactionId)
  		xidForceLimit -= FirstNormalTransactionId;
  
--- 1174,1183 ----
  	 */
  	recentXid = ReadNewTransactionId();
  	xidForceLimit = recentXid - autovacuum_freeze_max_age;
! 	/*
! 	 * Ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves.  This
! 	 * can cause the limit to go backwards by 3, but that's OK.
! 	 */
  	if (xidForceLimit < FirstNormalTransactionId)
  		xidForceLimit -= FirstNormalTransactionId;
  
***************
*** 1148,1153 **** do_start_worker(void)
--- 1196,1209 ----
  	 * if any is in MultiXactId wraparound.  Note that those in Xid wraparound
  	 * danger are given more priority than those in multi wraparound danger.
  	 *
+ 	 * (However, we ignore databases in danger of Xid or multixact wraparound
+ 	 * if a worker has recently been started in them and it is still working.
+ 	 * The rationale for this is that other databases might need attention even
+ 	 * if they are not in danger of wraparound, and starting another worker too
+ 	 * soon after the first one would give no benefit.  We disable this check
+ 	 * when autovacuum is nominally disabled, though, because in that mode the
+ 	 * only reason we're here is to process endangered databases.)
+ 	 *
  	 * Note that a database with no stats entry is not considered, except for
  	 * Xid wraparound purposes.  The theory is that if no one has ever
  	 * connected to it since the stats were last initialized, it doesn't need
***************
*** 1167,1192 **** do_start_worker(void)
  	foreach(cell, dblist)
  	{
  		avw_dbase  *tmp = lfirst(cell);
  		dlist_iter	iter;
  
! 		/* Check to see if this one is at risk of wraparound */
! 		if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit))
  		{
  			if (avdb == NULL ||
  				TransactionIdPrecedes(tmp->adw_frozenxid,
  									  avdb->adw_frozenxid))
  				avdb = tmp;
! 			for_xid_wrap = true;
  			continue;
  		}
  		else if (for_xid_wrap)
  			continue;			/* ignore not-at-risk DBs */
! 		else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit))
  		{
  			if (avdb == NULL ||
  				MultiXactIdPrecedes(tmp->adw_minmulti, avdb->adw_minmulti))
  				avdb = tmp;
! 			for_multi_wrap = true;
  			continue;
  		}
  		else if (for_multi_wrap)
--- 1223,1273 ----
  	foreach(cell, dblist)
  	{
  		avw_dbase  *tmp = lfirst(cell);
+ 		avl_dbase  *dbp = NULL;
  		dlist_iter	iter;
  
! 		/* Find this database's entry in the launcher's list, if any */
! 		dlist_reverse_foreach(iter, &DatabaseList)
! 		{
! 			avl_dbase  *db = dlist_container(avl_dbase, adl_node, iter.cur);
! 
! 			if (db->adl_datid == tmp->adw_datid)
! 			{
! 				dbp = db;
! 				break;
! 			}
! 		}
! 
! 		/* Check to see if this database is at risk of wraparound */
! 		if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit) &&
! 			(!AutoVacuumingActive() ||
! 			 !db_was_recently_processed(dbp, current_time,
! 										autovacuum_naptime * 1000 / 2) ||
! 			 !db_has_running_workers(dbp)))
  		{
  			if (avdb == NULL ||
  				TransactionIdPrecedes(tmp->adw_frozenxid,
  									  avdb->adw_frozenxid))
+ 			{
  				avdb = tmp;
! 				for_xid_wrap = true;
! 			}
  			continue;
  		}
  		else if (for_xid_wrap)
  			continue;			/* ignore not-at-risk DBs */
! 		else if (MultiXactIdPrecedes(tmp->adw_minmulti, multiForceLimit) &&
! 				 (!AutoVacuumingActive() ||
! 				  !db_was_recently_processed(dbp, current_time,
! 											 autovacuum_naptime * 1000 / 2) ||
! 				  !db_has_running_workers(dbp)))
  		{
  			if (avdb == NULL ||
  				MultiXactIdPrecedes(tmp->adw_minmulti, avdb->adw_minmulti))
+ 			{
  				avdb = tmp;
! 				for_multi_wrap = true;
! 			}
  			continue;
  		}
  		else if (for_multi_wrap)
***************
*** 1208,1238 **** do_start_worker(void)
  		 * We do this so that we don't select a database which we just
  		 * selected, but that pgstat hasn't gotten around to updating the last
  		 * autovacuum time yet.
  		 */
! 		skipit = false;
! 
! 		dlist_reverse_foreach(iter, &DatabaseList)
  		{
! 			avl_dbase  *dbp = dlist_container(avl_dbase, adl_node, iter.cur);
! 
! 			if (dbp->adl_datid == tmp->adw_datid)
! 			{
! 				/*
! 				 * Skip this database if its next_worker value falls between
! 				 * the current time and the current time plus naptime.
! 				 */
! 				if (!TimestampDifferenceExceeds(dbp->adl_next_worker,
! 												current_time, 0) &&
! 					!TimestampDifferenceExceeds(current_time,
! 												dbp->adl_next_worker,
! 												autovacuum_naptime * 1000))
! 					skipit = true;
! 
! 				break;
! 			}
! 		}
! 		if (skipit)
  			continue;
  
  		/*
  		 * Remember the db with oldest autovac time.  (If we are here, both
--- 1289,1304 ----
  		 * We do this so that we don't select a database which we just
  		 * selected, but that pgstat hasn't gotten around to updating the last
  		 * autovacuum time yet.
+ 		 *
+ 		 * Exact criterion is to skip if its next_worker value falls between
+ 		 * the current time and the current time plus naptime.
  		 */
! 		if (db_was_recently_processed(dbp, current_time,
! 									  autovacuum_naptime * 1000))
  		{
! 			skipped = true;
  			continue;
+ 		}
  
  		/*
  		 * Remember the db with oldest autovac time.  (If we are here, both
***************
*** 1270,1276 **** do_start_worker(void)
  
  		retval = avdb->adw_datid;
  	}
! 	else if (skipit)
  	{
  		/*
  		 * If we skipped all databases on the list, rebuild it, because it
--- 1336,1342 ----
  
  		retval = avdb->adw_datid;
  	}
! 	else if (skipped)
  	{
  		/*
  		 * If we skipped all databases on the list, rebuild it, because it
