*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 81,86 **** static void show_sort_keys_common(PlanState *planstate,
--- 81,87 ----
  					  List *ancestors, ExplainState *es);
  static void show_sort_info(SortState *sortstate, ExplainState *es);
  static void show_hash_info(HashState *hashstate, ExplainState *es);
+ static void show_bitmapscan_info(BitmapHeapScanState *planstate, ExplainState *es);
  static void show_instrumentation_count(const char *qlabel, int which,
  						   PlanState *planstate, ExplainState *es);
  static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es);
***************
*** 1246,1251 **** ExplainNode(PlanState *planstate, List *ancestors,
--- 1247,1254 ----
  			if (((BitmapHeapScan *) plan)->bitmapqualorig)
  				show_instrumentation_count("Rows Removed by Index Recheck", 2,
  										   planstate, es);
+ 			if (es->analyze)
+ 				show_bitmapscan_info((BitmapHeapScanState *) planstate, es);
  			/* FALL THRU */
  		case T_SeqScan:
  		case T_ValuesScan:
***************
*** 1814,1819 **** show_hash_info(HashState *hashstate, ExplainState *es)
--- 1817,1860 ----
  }
  
  /*
+  * If it's EXPLAIN ANALYZE, show information for a BitmapHeapScan node.
+  */
+ static void
+ show_bitmapscan_info(BitmapHeapScanState *planstate, ExplainState *es)
+ {
+ 	long		spacePeakKb = (planstate->tbm_spacePeak + 1023) / 1024;
+ 	long		spaceDesiredKb = (planstate->tbm_spaceDesired + 1023) / 1024;
+ 
+ 	if (es->format == EXPLAIN_FORMAT_TEXT)
+ 	{
+ 		appendStringInfoSpaces(es->str, es->indent * 2);
+ 		appendStringInfoString(es->str, "Heap Blocks:");
+ 		if (planstate->exact_pages > 0)
+ 			appendStringInfo(es->str, " exact=%ld", planstate->exact_pages);
+ 		if (planstate->lossy_pages > 0)
+ 			appendStringInfo(es->str, " lossy=%ld", planstate->lossy_pages);
+ 		appendStringInfoChar(es->str, '\n');
+ 		appendStringInfoSpaces(es->str, es->indent * 2);
+ 		appendStringInfo(es->str, "Bitmap Memory Usage: %ldkB", spacePeakKb);
+ 		if (planstate->tbm_lossified)
+ 		{
+ 			if (planstate->tbm_pageadded)
+ 				appendStringInfo(es->str, " (up to %ldkB desired)", spaceDesiredKb);
+ 			else
+ 				appendStringInfo(es->str, " (%ldkB desired)", spaceDesiredKb);
+ 		}
+ 		appendStringInfoChar(es->str, '\n');
+ 	}
+ 	else
+ 	{
+ 		ExplainPropertyLong("Exact Heap Blocks", planstate->exact_pages, es);
+ 		ExplainPropertyLong("Lossy Heap Blocks", planstate->lossy_pages, es);
+ 		ExplainPropertyLong("Peak Memory Usage", spacePeakKb, es);
+ 		ExplainPropertyLong("Desired Memory", spaceDesiredKb, es);
+ 	}
+ }
+ 
+ /*
   * If it's EXPLAIN ANALYZE, show instrumentation information for a plan node
   *
   * "which" identifies which instrumentation counter to print
*** a/src/backend/executor/nodeBitmapHeapscan.c
--- b/src/backend/executor/nodeBitmapHeapscan.c
***************
*** 101,106 **** BitmapHeapNext(BitmapHeapScanState *node)
--- 101,111 ----
  	 */
  	if (tbm == NULL)
  	{
+ 		long		spacePeak;
+ 		long		spaceDesired;
+ 		bool		lossified;
+ 		bool		pageadded;
+ 
  		tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
  
  		if (!tbm || !IsA(tbm, TIDBitmap))
***************
*** 110,115 **** BitmapHeapNext(BitmapHeapScanState *node)
--- 115,130 ----
  		node->tbmiterator = tbmiterator = tbm_begin_iterate(tbm);
  		node->tbmres = tbmres = NULL;
  
+ 		tbm_get_stats(tbm, &spacePeak, &spaceDesired, &lossified, &pageadded);
+ 		if (spacePeak > node->tbm_spacePeak)
+ 			node->tbm_spacePeak = spacePeak;
+ 		if (spaceDesired > node->tbm_spaceDesired)
+ 			node->tbm_spaceDesired = spaceDesired;
+ 		if (lossified)
+ 			node->tbm_lossified = true;
+ 		if (pageadded)
+ 			node->tbm_pageadded = true;
+ 
  #ifdef USE_PREFETCH
  		if (target_prefetch_pages > 0)
  		{
***************
*** 170,175 **** BitmapHeapNext(BitmapHeapScanState *node)
--- 185,195 ----
  			 */
  			bitgetpage(scan, tbmres);
  
+ 			if (tbmres->ntuples >= 0)
+ 				node->exact_pages++;
+ 			else
+ 				node->lossy_pages++;
+ 
  			/*
  			 * Set rs_cindex to first slot to examine
  			 */
***************
*** 556,561 **** ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
--- 576,587 ----
  	scanstate->prefetch_iterator = NULL;
  	scanstate->prefetch_pages = 0;
  	scanstate->prefetch_target = 0;
+ 	scanstate->exact_pages = 0;
+ 	scanstate->lossy_pages = 0;
+ 	scanstate->tbm_spacePeak = 0;
+ 	scanstate->tbm_spaceDesired = 0;
+ 	scanstate->tbm_lossified = false;
+ 	scanstate->tbm_pageadded = false;
  
  	/*
  	 * Miscellaneous initialization
*** a/src/backend/nodes/tidbitmap.c
--- b/src/backend/nodes/tidbitmap.c
***************
*** 130,138 **** struct TIDBitmap
--- 130,143 ----
  	TBMStatus	status;			/* see codes above */
  	HTAB	   *pagetable;		/* hash table of PagetableEntry's */
  	int			nentries;		/* number of entries in pagetable */
+ 	int			nentriesPeak;	/* peak number of entries in pagetable */
  	int			maxentries;		/* limit on same to meet maxbytes */
  	int			npages;			/* number of exact entries in pagetable */
  	int			nchunks;		/* number of lossy entries in pagetable */
+ 	int			totalpages;		/* total number of exact/loosy pages */
+ 	int			totalpagesPeak;	/* peak total number of exact/lossy pages */
+ 	bool		lossified;		/* tbm_lossify called? */
+ 	bool		pageadded;		/* tbm_add_page called? */
  	bool		iterating;		/* tbm_begin_iterate called? */
  	PagetableEntry entry1;		/* used when status == TBM_ONE_PAGE */
  	/* these are valid when iterating is true: */
***************
*** 293,298 **** tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids,
--- 298,306 ----
  		{
  			/* The page is a lossy chunk header, set bit for itself */
  			wordnum = bitnum = 0;
+ 			tbm->totalpages++;
+ 			if (tbm->totalpages > tbm->totalpagesPeak)
+ 				tbm->totalpagesPeak = tbm->totalpages;
  		}
  		else
  		{
***************
*** 317,322 **** tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids,
--- 325,331 ----
  void
  tbm_add_page(TIDBitmap *tbm, BlockNumber pageno)
  {
+ 	tbm->pageadded = true;
  	/* Enter the page in the bitmap, or mark it lossy if already present */
  	tbm_mark_page_lossy(tbm, pageno);
  	/* If we went over the memory limit, lossify some more pages */
***************
*** 333,338 **** void
--- 342,355 ----
  tbm_union(TIDBitmap *a, const TIDBitmap *b)
  {
  	Assert(!a->iterating);
+ 	if (a->nentriesPeak < b->nentriesPeak)
+ 		a->nentriesPeak = b->nentriesPeak;
+ 	if (a->totalpagesPeak < b->totalpagesPeak)
+ 		a->totalpagesPeak = b->totalpagesPeak;
+ 	if (b->lossified)
+ 		a->lossified = b->lossified;
+ 	if (b->pageadded)
+ 		a->pageadded = b->pageadded;
  	/* Nothing to do if b is empty */
  	if (b->nentries == 0)
  		return;
***************
*** 392,397 **** tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage)
--- 409,417 ----
  		{
  			/* The page is a lossy chunk header, set bit for itself */
  			apage->words[0] |= ((bitmapword) 1 << 0);
+ 			a->totalpages++;
+ 			if (a->totalpages > a->totalpagesPeak)
+ 				a->totalpagesPeak = a->totalpages;
  		}
  		else
  		{
***************
*** 415,420 **** void
--- 435,448 ----
  tbm_intersect(TIDBitmap *a, const TIDBitmap *b)
  {
  	Assert(!a->iterating);
+ 	if (a->nentriesPeak < b->nentriesPeak)
+ 		a->nentriesPeak = b->nentriesPeak;
+ 	if (a->totalpagesPeak < b->totalpagesPeak)
+ 		a->totalpagesPeak = b->totalpagesPeak;
+ 	if (b->lossified)
+ 		a->lossified = b->lossified;
+ 	if (b->pageadded)
+ 		a->pageadded = b->pageadded;
  	/* Nothing to do if a is empty */
  	if (a->nentries == 0)
  		return;
***************
*** 494,499 **** tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
--- 522,528 ----
  						{
  							/* Page is not in b at all, lose lossy bit */
  							neww &= ~((bitmapword) 1 << bitnum);
+ 							a->totalpages--;
  						}
  					}
  					pg++;
***************
*** 536,541 **** tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
--- 565,572 ----
  			apage->recheck |= bpage->recheck;
  		}
  		/* If there is no matching b page, we can just delete the a page */
+ 		if (candelete)
+ 			a->totalpages--;
  		return candelete;
  	}
  }
***************
*** 754,759 **** tbm_end_iterate(TBMIterator *iterator)
--- 785,812 ----
  }
  
  /*
+  * tbm_get_stats - extract summary statistics
+  *
+  * spacePeak and spaceDesired are measured in bytes respectively.
+  */
+ void
+ tbm_get_stats(const TIDBitmap *tbm,
+ 			  long *spacePeak,
+ 			  long *spaceDesired,
+ 			  bool *lossified,
+ 			  bool *pageadded)
+ {
+ 	*spacePeak = tbm->nentriesPeak *
+ 		(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ 		 + sizeof(Pointer) + sizeof(Pointer));
+ 	*spaceDesired = tbm->totalpagesPeak *
+ 		(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ 		 + sizeof(Pointer) + sizeof(Pointer));
+ 	*lossified = tbm->lossified;
+ 	*pageadded = tbm->pageadded;
+ }
+ 
+ /*
   * tbm_find_pageentry - find a PagetableEntry for the pageno
   *
   * Returns NULL if there is no non-lossy entry for the pageno.
***************
*** 829,836 **** tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno)
--- 882,894 ----
  		MemSet(page, 0, sizeof(PagetableEntry));
  		page->blockno = pageno;
  		/* must count it too */
+ 		tbm->totalpages++;
  		tbm->nentries++;
  		tbm->npages++;
+ 		if (tbm->totalpages > tbm->totalpagesPeak)
+ 			tbm->totalpagesPeak = tbm->totalpages;
+ 		if (tbm->nentries > tbm->nentriesPeak)
+ 			tbm->nentriesPeak = tbm->nentries;
  	}
  
  	return page;
***************
*** 901,906 **** tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno)
--- 959,965 ----
  						HASH_REMOVE, NULL) != NULL)
  		{
  			/* It was present, so adjust counts */
+ 			tbm->totalpages--;
  			tbm->nentries--;
  			tbm->npages--;		/* assume it must have been non-lossy */
  		}
***************
*** 920,925 **** tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno)
--- 979,986 ----
  		/* must count it too */
  		tbm->nentries++;
  		tbm->nchunks++;
+ 		if (tbm->nentries > tbm->nentriesPeak)
+ 			tbm->nentriesPeak = tbm->nentries;
  	}
  	else if (!page->ischunk)
  	{
***************
*** 937,943 **** tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno)
  	/* Now set the original target page's bit */
  	wordnum = WORDNUM(bitno);
  	bitnum = BITNUM(bitno);
! 	page->words[wordnum] |= ((bitmapword) 1 << bitnum);
  }
  
  /*
--- 998,1010 ----
  	/* Now set the original target page's bit */
  	wordnum = WORDNUM(bitno);
  	bitnum = BITNUM(bitno);
! 	if ((page->words[wordnum] & ((bitmapword) 1 << bitnum)) == 0)
! 	{
! 		page->words[wordnum] |= ((bitmapword) 1 << bitnum);
! 		tbm->totalpages++;
! 		if (tbm->totalpages > tbm->totalpagesPeak)
! 			tbm->totalpagesPeak = tbm->totalpages;
! 	}
  }
  
  /*
***************
*** 960,965 **** tbm_lossify(TIDBitmap *tbm)
--- 1027,1033 ----
  	 */
  	Assert(!tbm->iterating);
  	Assert(tbm->status == TBM_HASH);
+ 	tbm->lossified = true;
  
  	hash_seq_init(&status, tbm->pagetable);
  	while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL)
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 1352,1357 **** typedef struct BitmapHeapScanState
--- 1352,1363 ----
  	TBMIterator *prefetch_iterator;
  	int			prefetch_pages;
  	int			prefetch_target;
+ 	long		exact_pages;
+ 	long		lossy_pages;
+ 	long		tbm_spacePeak;
+ 	long		tbm_spaceDesired;
+ 	bool		tbm_lossified;
+ 	bool		tbm_pageadded;
  } BitmapHeapScanState;
  
  /* ----------------
*** a/src/include/nodes/tidbitmap.h
--- b/src/include/nodes/tidbitmap.h
***************
*** 63,66 **** extern TBMIterator *tbm_begin_iterate(TIDBitmap *tbm);
--- 63,72 ----
  extern TBMIterateResult *tbm_iterate(TBMIterator *iterator);
  extern void tbm_end_iterate(TBMIterator *iterator);
  
+ extern void tbm_get_stats(const TIDBitmap *tbm,
+ 						  long *spacePeak,
+ 						  long *spaceDesired,
+ 						  bool *lossified,
+ 						  bool *pageadded);
+ 
  #endif   /* TIDBITMAP_H */
