*** a/src/backend/commands/explain.c --- b/src/backend/commands/explain.c *************** *** 81,86 **** static void show_sort_keys_common(PlanState *planstate, --- 81,88 ---- 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_tidbitmap_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,1252 **** ExplainNode(PlanState *planstate, List *ancestors, if (((BitmapHeapScan *) plan)->bitmapqualorig) show_instrumentation_count("Rows Removed by Index Recheck", 2, planstate, es); ! /* FALL THRU */ case T_SeqScan: case T_ValuesScan: case T_CteScan: --- 1248,1260 ---- if (((BitmapHeapScan *) plan)->bitmapqualorig) show_instrumentation_count("Rows Removed by Index Recheck", 2, planstate, es); ! show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); ! if (plan->qual) ! show_instrumentation_count("Rows Removed by Filter", 1, ! planstate, es); ! if (es->analyze) ! show_tidbitmap_info((BitmapHeapScanState *) planstate, es); ! break; case T_SeqScan: case T_ValuesScan: case T_CteScan: *************** *** 1814,1819 **** show_hash_info(HashState *hashstate, ExplainState *es) --- 1822,1853 ---- } /* + * Show information on a TIDBitmap. + */ + static void + show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es) + { + long tbmspaceKb = (planstate->tbmspace + 1023) / 1024; + + if (es->format != EXPLAIN_FORMAT_TEXT) + { + ExplainPropertyLong("Exact Blocks", planstate->exact_pages, es); + ExplainPropertyLong("Lossy Blocks", planstate->lossy_pages, es); + ExplainPropertyLong("Bitmap Memory", tbmspaceKb, es); + } + else + { + appendStringInfoSpaces(es->str, es->indent * 2); + appendStringInfoString(es->str, "Fetch 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); + appendStringInfo(es->str, " Bitmap Memory: %ldkB\n", tbmspaceKb); + } + } + + /* * 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,108 ---- */ if (tbm == NULL) { + long tbmspace; + tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node)); if (!tbm || !IsA(tbm, TIDBitmap)) *************** *** 110,115 **** BitmapHeapNext(BitmapHeapScanState *node) --- 112,121 ---- node->tbmiterator = tbmiterator = tbm_begin_iterate(tbm); node->tbmres = tbmres = NULL; + tbmspace = tbm_get_space(tbm); + if (tbmspace > node->tbmspace) + node->tbmspace = tbmspace; + #ifdef USE_PREFETCH if (target_prefetch_pages > 0) { *************** *** 170,175 **** BitmapHeapNext(BitmapHeapScanState *node) --- 176,186 ---- */ bitgetpage(scan, tbmres); + if (tbmres->ntuples >= 0) + node->exact_pages++; + else + node->lossy_pages++; + /* * Set rs_cindex to first slot to examine */ *************** *** 553,558 **** ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) --- 564,572 ---- scanstate->tbm = NULL; scanstate->tbmiterator = NULL; scanstate->tbmres = NULL; + scanstate->tbmspace = 0; + scanstate->exact_pages = 0; + scanstate->lossy_pages = 0; scanstate->prefetch_iterator = NULL; scanstate->prefetch_pages = 0; scanstate->prefetch_target = 0; *** a/src/backend/nodes/tidbitmap.c --- b/src/backend/nodes/tidbitmap.c *************** *** 131,136 **** struct TIDBitmap --- 131,137 ---- HTAB *pagetable; /* hash table of PagetableEntry's */ int nentries; /* number of entries in pagetable */ int maxentries; /* limit on same to meet maxbytes */ + int nentriesPeak; /* greatest on same */ int npages; /* number of exact entries in pagetable */ int nchunks; /* number of lossy entries in pagetable */ bool iterating; /* tbm_begin_iterate called? */ *************** *** 333,338 **** void --- 334,341 ---- tbm_union(TIDBitmap *a, const TIDBitmap *b) { Assert(!a->iterating); + if (a->nentriesPeak < b->nentriesPeak) + a->nentriesPeak = b->nentriesPeak; /* Nothing to do if b is empty */ if (b->nentries == 0) return; *************** *** 415,420 **** void --- 418,425 ---- tbm_intersect(TIDBitmap *a, const TIDBitmap *b) { Assert(!a->iterating); + if (a->nentriesPeak < b->nentriesPeak) + a->nentriesPeak = b->nentriesPeak; /* Nothing to do if a is empty */ if (a->nentries == 0) return; *************** *** 754,759 **** tbm_end_iterate(TBMIterator *iterator) --- 759,775 ---- } /* + * tbm_get_space - get (peak) TIDBitmap memory usage in bytes + */ + long + tbm_get_space(const TIDBitmap *tbm) + { + return (long) tbm->nentriesPeak * + (MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry)) + + sizeof(Pointer) + sizeof(Pointer)); + } + + /* * tbm_find_pageentry - find a PagetableEntry for the pageno * * Returns NULL if there is no non-lossy entry for the pageno. *************** *** 831,836 **** tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno) --- 847,854 ---- /* must count it too */ tbm->nentries++; tbm->npages++; + if (tbm->nentries > tbm->nentriesPeak) + tbm->nentriesPeak = tbm->nentries; } return page; *************** *** 920,925 **** tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno) --- 938,945 ---- /* must count it too */ tbm->nentries++; tbm->nchunks++; + if (tbm->nentries > tbm->nentriesPeak) + tbm->nentriesPeak = tbm->nentries; } else if (!page->ischunk) { *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 1337,1342 **** typedef struct BitmapIndexScanState --- 1337,1345 ---- * tbm bitmap obtained from child index scan(s) * tbmiterator iterator for scanning current pages * tbmres current-page data + * tbmspace (peak) bitmap memory usage + * exact_pages # exact pages + * lossy_pages # lossy pages * prefetch_iterator iterator for prefetching ahead of current page * prefetch_pages # pages prefetch iterator is ahead of current * prefetch_target target prefetch distance *************** *** 1349,1354 **** typedef struct BitmapHeapScanState --- 1352,1360 ---- TIDBitmap *tbm; TBMIterator *tbmiterator; TBMIterateResult *tbmres; + long tbmspace; + long exact_pages; + long lossy_pages; TBMIterator *prefetch_iterator; int prefetch_pages; int prefetch_target; *** a/src/include/nodes/tidbitmap.h --- b/src/include/nodes/tidbitmap.h *************** *** 63,66 **** extern TBMIterator *tbm_begin_iterate(TIDBitmap *tbm); --- 63,68 ---- extern TBMIterateResult *tbm_iterate(TBMIterator *iterator); extern void tbm_end_iterate(TBMIterator *iterator); + extern long tbm_get_space(const TIDBitmap *tbm); + #endif /* TIDBITMAP_H */