Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

Started by Etsuro Fujitaabout 12 years ago20 messages
#1Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
1 attachment(s)

Hi,

I think that lossy-heap-block information for a bitmap heap scan, not just "Rows
Removed by Index Recheck" information, would also be a clue used to tune
work_mem for better performance especially when the bitmap heap scan uses an
index such as gin or gist, not btree.

So here's a patch that adds the information to the EXPLAIN ANALYZE output. The
following shows an example. The number of lossy-heap-block fetches (ie
tbmres->ntuples = -1) as well as that of exact-heap-block fetches (ie
tbmres->ntuples >= 0) are shown in the "Heap Blocks" line.

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and 0.02;
QUERY PLAN
--------------------------------------------------------------------------------
------------------------------------------------
Bitmap Heap Scan on demo (cost=2716.54..92075.46 rows=105766 width=34) (actual
time=24.907..1119.961 rows=100047 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Rows Removed by Index Recheck: 5484114
Heap Blocks: exact=11975 lossy=46388
-> Bitmap Index Scan on demo_idx (cost=0.00..2690.09 rows=105766 width=0)
(actual time=22.821..22.821 rows=100047 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Total runtime: 1129.334 ms
(7 rows)

Comments welcome.

Thanks,

Best regards,
Etsuro Fujita

Attachments:

explain-bitmapscan-20131031.patchapplication/octet-stream; name=explain-bitmapscan-20131031.patchDownload
*** 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_heap_pages(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_heap_pages((BitmapHeapScanState *) planstate, es);
  			/* FALL THRU */
  		case T_SeqScan:
  		case T_ValuesScan:
***************
*** 1814,1819 **** show_hash_info(HashState *hashstate, ExplainState *es)
--- 1817,1845 ----
  }
  
  /*
+  * If it's EXPLAIN ANALYZE, show heap page fetches for a BitmapHeapScan node
+  */
+ static void
+ show_heap_pages(BitmapHeapScanState *planstate, ExplainState *es)
+ {
+ 	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');
+ 	}
+ 	else
+ 	{
+ 		ExplainPropertyLong("Exact Heap Blocks", planstate->exact_pages, es);
+ 		ExplainPropertyLong("Lossy Heap Blocks", planstate->lossy_pages, 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
***************
*** 170,175 **** BitmapHeapNext(BitmapHeapScanState *node)
--- 170,180 ----
  			 */
  			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)
--- 561,568 ----
  	scanstate->prefetch_iterator = NULL;
  	scanstate->prefetch_pages = 0;
  	scanstate->prefetch_target = 0;
+ 	scanstate->exact_pages = 0;
+ 	scanstate->lossy_pages = 0;
  
  	/*
  	 * Miscellaneous initialization
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 1352,1357 **** typedef struct BitmapHeapScanState
--- 1352,1359 ----
  	TBMIterator *prefetch_iterator;
  	int			prefetch_pages;
  	int			prefetch_target;
+ 	long		exact_pages;
+ 	long		lossy_pages;
  } BitmapHeapScanState;
  
  /* ----------------
#2Fujii Masao
masao.fujii@gmail.com
In reply to: Etsuro Fujita (#1)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On Thu, Oct 31, 2013 at 7:54 PM, Etsuro Fujita
<fujita.etsuro@lab.ntt.co.jp> wrote:

Hi,

I think that lossy-heap-block information for a bitmap heap scan, not just "Rows
Removed by Index Recheck" information, would also be a clue used to tune
work_mem for better performance especially when the bitmap heap scan uses an
index such as gin or gist, not btree.

So here's a patch that adds the information to the EXPLAIN ANALYZE output. The
following shows an example. The number of lossy-heap-block fetches (ie
tbmres->ntuples = -1) as well as that of exact-heap-block fetches (ie
tbmres->ntuples >= 0) are shown in the "Heap Blocks" line.

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and 0.02;
QUERY PLAN
--------------------------------------------------------------------------------
------------------------------------------------
Bitmap Heap Scan on demo (cost=2716.54..92075.46 rows=105766 width=34) (actual
time=24.907..1119.961 rows=100047 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Rows Removed by Index Recheck: 5484114
Heap Blocks: exact=11975 lossy=46388
-> Bitmap Index Scan on demo_idx (cost=0.00..2690.09 rows=105766 width=0)
(actual time=22.821..22.821 rows=100047 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Total runtime: 1129.334 ms
(7 rows)

Comments welcome.

This is what I'm looking for! This feature is really useful for tuning work_mem
when using full text search with pg_trgm.

I'm not sure if it's good idea to show the number of the fetches because
it seems difficult to tune work_mem from that number. How can we calculate
how much to increase work_mem to avoid lossy bitmap from the number of
the fetches in EXPLAIN output?

Anyway, could you add the patch into next CF?

Regards,

--
Fujii Masao

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Fujii Masao (#2)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

From: Fujii Masao [mailto:masao.fujii@gmail.com]

This is what I'm looking for! This feature is really useful for tuning

work_mem

when using full text search with pg_trgm.

I'm not sure if it's good idea to show the number of the fetches because it
seems difficult to tune work_mem from that number. How can we calculate how
much to increase work_mem to avoid lossy bitmap from the number of the fetches
in EXPLAIN output?

We can calculate that from the following equation in tbm_create():

nbuckets = maxbytes /
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)),

where maxbytes is the size of memory used for the hashtable in a TIDBitmap,
designated by work_mem, and nbuckets is the estimated number of hashtable
entries we can have within maxbytes. From this, the size of work_mem within
which we can have every hashtable entry as an exact bitmap is calculated as
follows:

work_mem = (the number of exact pages + the number of lossy pages) *
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)) /
(1024 * 1024).

I'll show you an example. The following is the result for work_mem = 1MB:

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and

0.02;

QUERY PLAN
----------------------------------------------------------------------
----------
------------------------------------------------
Bitmap Heap Scan on demo (cost=2716.54..92075.46 rows=105766
width=34) (actual
time=24.907..1119.961 rows=100047 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double
precision))
Rows Removed by Index Recheck: 5484114
Heap Blocks: exact=11975 lossy=46388
-> Bitmap Index Scan on demo_idx (cost=0.00..2690.09 rows=105766
width=0) (actual time=22.821..22.821 rows=100047 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double
precision))
Total runtime: 1129.334 ms
(7 rows)

So, by setting work_mem to

work_mem = (11975 + 46388) *
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)) /
(1024 * 1024),

which is about 5MB, we have the following (Note that no lossy heap pages!):

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and 0.02;
QUERY PLAN

--------------------------------------------------------------------------------
----------------------------
--------------------
Bitmap Heap Scan on demo (cost=2716.54..92075.46 rows=105766 width=34) (actual
time=42.981..120.252 rows=1
00047 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Heap Blocks: exact=58363
-> Bitmap Index Scan on demo_idx (cost=0.00..2690.09 rows=105766 width=0)
(actual time=26.023..26.023 r
ows=100047 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Total runtime: 129.304 ms
(6 rows)

BTW, as the EXPLAIN ANALYZE output, the number of exact/lossy heap pages would
be fine with me.

Anyway, could you add the patch into next CF?

Done.

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Amit Khandekar
amit.khandekar@enterprisedb.com
In reply to: Etsuro Fujita (#3)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On 1 November 2013 16:32, Etsuro Fujita <fujita.etsuro@lab.ntt.co.jp> wrote:

From: Fujii Masao [mailto:masao.fujii@gmail.com]

This is what I'm looking for! This feature is really useful for tuning

work_mem

when using full text search with pg_trgm.

I'm not sure if it's good idea to show the number of the fetches because

it

seems difficult to tune work_mem from that number. How can we calculate

how

much to increase work_mem to avoid lossy bitmap from the number of the

fetches

in EXPLAIN output?

We can calculate that from the following equation in tbm_create():

nbuckets = maxbytes /
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)),

where maxbytes is the size of memory used for the hashtable in a TIDBitmap,
designated by work_mem, and nbuckets is the estimated number of hashtable
entries we can have within maxbytes. From this, the size of work_mem
within
which we can have every hashtable entry as an exact bitmap is calculated as
follows:

work_mem = (the number of exact pages + the number of lossy pages) *
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)) /
(1024 * 1024).

I am yet to give more thought on the above formula (particularly
exact_pages + lossy_pages), but I was also wondering if the user would
indeed be able to figure out the above way to estimate the memory, or the
explain itself should show the estimated memory required for the bitmap.
For hash joins we do show the memory taken by the hash table in
show_hash_info(). We can show the memory requirement in addition to the
number of exact/lossy pages.

Show quoted text

I'll show you an example. The following is the result for work_mem = 1MB:

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01

and

0.02;

QUERY PLAN
----------------------------------------------------------------------
----------
------------------------------------------------
Bitmap Heap Scan on demo (cost=2716.54..92075.46 rows=105766
width=34) (actual
time=24.907..1119.961 rows=100047 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double
precision))
Rows Removed by Index Recheck: 5484114
Heap Blocks: exact=11975 lossy=46388
-> Bitmap Index Scan on demo_idx (cost=0.00..2690.09 rows=105766
width=0) (actual time=22.821..22.821 rows=100047 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double
precision))
Total runtime: 1129.334 ms
(7 rows)

So, by setting work_mem to

work_mem = (11975 + 46388) *
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)) /
(1024 * 1024),

which is about 5MB, we have the following (Note that no lossy heap pages!):

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and
0.02;
QUERY PLAN

--------------------------------------------------------------------------------
----------------------------
--------------------
Bitmap Heap Scan on demo (cost=2716.54..92075.46 rows=105766 width=34)
(actual
time=42.981..120.252 rows=1
00047 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double
precision))
Heap Blocks: exact=58363
-> Bitmap Index Scan on demo_idx (cost=0.00..2690.09 rows=105766
width=0)
(actual time=26.023..26.023 r
ows=100047 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double
precision))
Total runtime: 129.304 ms
(6 rows)

BTW, as the EXPLAIN ANALYZE output, the number of exact/lossy heap pages
would
be fine with me.

Anyway, could you add the patch into next CF?

Done.

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Amit Khandekar (#4)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

From: Amit Khandekar [mailto:amit.khandekar@enterprisedb.com]

On 1 November 2013 16:32, Etsuro Fujita <fujita.etsuro@lab.ntt.co.jp> wrote:

From: Fujii Masao [mailto:masao.fujii@gmail.com]

I'm not sure if it's good idea to show the number of the fetches because it
seems difficult to tune work_mem from that number. How can we calculate how
much to increase work_mem to avoid lossy bitmap from the number of the fetches
in EXPLAIN output?

We can calculate that from the following equation in tbm_create():

nbuckets = maxbytes /
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)),

where maxbytes is the size of memory used for the hashtable in a TIDBitmap,
designated by work_mem, and nbuckets is the estimated number of hashtable
entries we can have within maxbytes. From this, the size of work_mem within
which we can have every hashtable entry as an exact bitmap is calculated as
follows:

work_mem = (the number of exact pages + the number of lossy pages) *
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer)) /
(1024 * 1024).

I am yet to give more thought on the above formula
(particularly exact_pages + lossy_pages), but I was also wondering if the user
would indeed be able to figure out the above way to estimate the memory, or the
explain itself should show the estimated memory required for the bitmap. For
hash joins we do show the memory taken by the hash table in show_hash_info(). We
can show the memory requirement in addition to the number of exact/lossy pages.

Thank you for the review!

Reconsidering that, I wish to know your opinion. The patch shows the number of exact/lossy pages that has been fetched in a bitmap heap scan. But the number varies with the fraction of tuples to be retrieved like the following.

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and 0.02;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on demo (cost=2187.35..101419.96 rows=102919 width=42) (actual time=23.684..1302.382 rows=99803 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double precision))
Rows Removed by Index Recheck: 6279502
Heap Blocks: exact=1990 lossy=59593
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..2161.62 rows=102919 width=0) (actual time=23.330..23.330 rows=99803 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double precision))
Total runtime: 1311.949 ms
(7 rows)

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and 0.02 LIMIT 5000;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=2187.35..7008.26 rows=5000 width=42) (actual time=23.543..86.093 rows=5000 loops=1)
-> Bitmap Heap Scan on demo (cost=2187.35..101419.96 rows=102919 width=42) (actual time=23.542..85.196 rows=5000 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double precision))
Rows Removed by Index Recheck: 312179
Heap Blocks: exact=99 lossy=2963
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..2161.62 rows=102919 width=0) (actual time=23.189..23.189 rows=99803 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double precision))
Total runtime: 86.626 ms
(8 rows)

So, my question is, we should show the number of exact/lossy pages in a TIDBitmap, not the number of these pages that has been fetched in the bitmap heap scan?

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Amit Khandekar
amit.khandekar@enterprisedb.com
In reply to: Etsuro Fujita (#1)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On 25 November 2013 13:37, Etsuro Fujita <fujita.etsuro@lab.ntt.co.jp>wrote:

Reconsidering that, I wish to know your opinion. The patch shows the
number of exact/lossy pages that has been fetched in a bitmap heap scan.
But the number varies with the fraction of tuples to be retrieved like the
following.

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and
0.02;
QUERY PLAN

------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on demo (cost=2187.35..101419.96 rows=102919 width=42)
(actual time=23.684..1302.382 rows=99803 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double precision))
Rows Removed by Index Recheck: 6279502
Heap Blocks: exact=1990 lossy=59593
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..2161.62 rows=102919
width=0) (actual time=23.330..23.330 rows=99803 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double precision))
Total runtime: 1311.949 ms
(7 rows)

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and
0.02 LIMIT 5000;
QUERY PLAN

------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=2187.35..7008.26 rows=5000 width=42) (actual
time=23.543..86.093 rows=5000 loops=1)
-> Bitmap Heap Scan on demo (cost=2187.35..101419.96 rows=102919
width=42) (actual time=23.542..85.196 rows=5000 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double precision))
Rows Removed by Index Recheck: 312179
Heap Blocks: exact=99 lossy=2963
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..2161.62
rows=102919 width=0) (actual time=23.189..23.189 rows=99803 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double precision))
Total runtime: 86.626 ms
(8 rows)

So, my question is, we should show the number of exact/lossy pages in a
TIDBitmap, not the number of these pages that has been fetched in the
bitmap heap scan?

Yes, I agree that rather than looking at the bitmap heap scan to track the
number of pages, we should look somewhere in the underlying index scan.
Yes, we should get a constant number of index pages regardless of the
actual parent table rows. I can see that btgetbitmap() adds all the tuples
into the bitmap, so somewhere below under btgetbitmap() might be the right
place to track. Somewhere in tbm_create_pagetable(), but not sure.

Show quoted text

Thanks,

Best regards,
Etsuro Fujita

#7Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Amit Khandekar (#6)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

Amit Khandekar wrote:

On 25 November 2013 13:37, Etsuro Fujita <fujita.etsuro@lab.ntt.co.jp> wrote:

So, my question is, we should show the number of exact/lossy pages in a
TIDBitmap, not the number of these pages that has been fetched in the bitmap
heap scan?

Yes, I agree that rather than looking at the bitmap heap scan to track the
number of pages, we should look somewhere in the underlying index scan. Yes,
we should get a constant number of index pages regardless of the actual
parent table rows. I can see that btgetbitmap() adds all the tuples into the
bitmap, so somewhere below under btgetbitmap() might be the right place to
track. Somewhere in tbm_create_pagetable(), but not sure.

Thank you for the comment!

I agree with you. I'll modify the patch to show 1) the number of the exact/lossy pages in a TIDBitmap by examining the underlying index scan, not the number of these pages that have been fetched in the bitmap heap scan, and 2) the memory requirement.

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Etsuro Fujita (#7)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

I wrote:

Amit Khandekar wrote:

Yes, I agree that rather than looking at the bitmap heap scan to track
the number of pages, we should look somewhere in the underlying index
scan. Yes, we should get a constant number of index pages regardless
of the actual parent table rows.

I agree with you. I'll modify the patch to show 1) the number of the
exact/lossy pages in a TIDBitmap by examining the underlying index scan,
not the number of these pages that have been fetched in the bitmap heap
scan, and 2) the memory requirement.

Though at first I agreed on this, while working on this I start to think information about (2) is enough for tuning work_mem. Here are examples using a version under development, where "Bitmap Memory Usage" means (peak) memory space used by a TIDBitmap, and "Desired" means the memory required to guarantee non-lossy storage of a TID set, which is shown only when the TIDBitmap has been lossified. (work_mem = 1MB.)

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.0001 and 0.0005 ;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on demo (cost=77.14..12142.69 rows=3581 width=42) (actual time=1.748..53.203 rows=4112 loops=1)
Recheck Cond: ((col2 >= 0.0001::double precision) AND (col2 <= 0.0005::double precision))
Bitmap Memory Usage: 315kB
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..76.25 rows=3581 width=0) (actual time=1.113..1.113 rows=4112 loops=1)
Index Cond: ((col2 >= 0.0001::double precision) AND (col2 <= 0.0005::double precision))
Total runtime: 53.804 ms
(6 rows)

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and 0.05 ;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on demo (cost=8307.41..107635.14 rows=391315 width=42) (actual time=84.818..2709.015 rows=400172 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.05::double precision))
Rows Removed by Index Recheck: 8815752
Bitmap Memory Usage: 1025kB (desired 20573kB)
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..8209.58 rows=391315 width=0) (actual time=83.664..83.664 rows=400172 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.05::double precision))
Total runtime: 2747.088 ms
(7 rows)

We should look at (1) as well? (Honestly, I don't know what to show about (1) when using a bitmap scan on the inside of a nestloop join. For memory usage and desired memory I think the maximum values would be fine.) I re-wish to know your opinion.

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Robert Haas
robertmhaas@gmail.com
In reply to: Etsuro Fujita (#1)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On Fri, Dec 6, 2013 at 5:02 AM, Etsuro Fujita
<fujita.etsuro@lab.ntt.co.jp> wrote:

Though at first I agreed on this, while working on this I start to think information about (2) is enough for tuning work_mem. Here are examples using a version under development, where "Bitmap Memory Usage" means (peak) memory space used by a TIDBitmap, and "Desired" means the memory required to guarantee non-lossy storage of a TID set, which is shown only when the TIDBitmap has been lossified. (work_mem = 1MB.)

I'd be wary of showing a desired value unless it's highly likely to be accurate.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Robert Haas (#9)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

Robert Haas wrote:

On Fri, Dec 6, 2013 at 5:02 AM, Etsuro Fujita

<fujita.etsuro@lab.ntt.co.jp>

wrote:

Though at first I agreed on this, while working on this I start to
think information about (2) is enough for tuning work_mem. Here are
examples using a version under development, where "Bitmap Memory
Usage" means (peak) memory space used by a TIDBitmap, and "Desired"
means the memory required to guarantee non-lossy storage of a TID set,
which is shown only when the TIDBitmap has been lossified. (work_mem
= 1MB.)

I'd be wary of showing a desired value unless it's highly likely to be
accurate.

Thank you for the comments!

The desired value is accurately estimated based on (a) the total number of
exact/lossy pages stored in the TIDBitmap and (b) the following equation in
tbm_create(), except for the GIN case where lossy pages are added to the
TIDBitmap by tbm_add_page().

/*
* Estimate number of hashtable entries we can have within maxbytes. ...
*/
nbuckets = maxbytes /
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer));

In the GIN case, however, the version under development has a risk of the
overestimation. (And in that case, in my understanding, we can't guarantee
non-lossy storage of the TIDBitmap any more.) So, for that case, I think to
change the message for the desired value a bit. I'll submit the patch
later.

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Etsuro Fujita (#10)
1 attachment(s)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

I wrote:

Robert Haas wrote:

I'd be wary of showing a desired value unless it's highly likely to be
accurate.

The desired value is accurately estimated based on (a) the total number
of exact/lossy pages stored in the TIDBitmap and (b) the following

equation

in tbm_create(), except for the GIN case where lossy pages are added to
the TIDBitmap by tbm_add_page().

/*
* Estimate number of hashtable entries we can have within maxbytes.

...

*/
nbuckets = maxbytes /
(MAXALIGN(sizeof(HASHELEMENT)) +
MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer) + sizeof(Pointer));

In the GIN case, however, the version under development has a risk of the
overestimation. (And in that case, in my understanding, we can't

guarantee

non-lossy storage of the TIDBitmap any more.) So, for that case, I think
to change the message for the desired value a bit. I'll submit the patch
later.

On second thoughts, I've modified the patch so that the EXPLAIN ANALYZE
command shows not only the desired value but the total number of exact/lossy
heap blocks that have been fetched in query execution because ISTM the
latter is also useful for tuning work_mem, when an available memory capacity
is not so large as the desired value, or when non-lossy storage of the
TIDBitmap can't be guaranteed as mentioned above. Here is an example.
Attached is an updated version of the patch, though a sufficient test hasn't
been performed.

postgres=# EXPLAIN ANALYZE SELECT * FROM demo WHERE col2 between 0.01 and
0.02 ;
QUERY PLAN
----------------------------------------------------------------------------
-------------------------------------------------------
Bitmap Heap Scan on demo (cost=2072.10..100674.45 rows=97528 width=42)
(actual time=27.387..1677.511 rows=99833 loops=1)
Recheck Cond: ((col2 >= 0.01::double precision) AND (col2 <= 0.02::double
precision))
Rows Removed by Index Recheck: 5581690
Heap Blocks: exact=8585 lossy=52980
Bitmap Memory Usage: 1025kB (4810kB desired)
-> Bitmap Index Scan on demo_col2_idx (cost=0.00..2047.71 rows=97528
width=0) (actual time=25.884..25.884 rows=99833 loops=1)
Index Cond: ((col2 >= 0.01::double precision) AND (col2 <=
0.02::double precision))
Total runtime: 1687.047 ms
(8 rows)

Thanks,

Best regards,
Etsuro Fujita

Attachments:

explain-bitmapscan-20131213.patchapplication/octet-stream; name=explain-bitmapscan-20131213.patchDownload
*** 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 */
#12Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Etsuro Fujita (#11)
1 attachment(s)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

I wrote:

Robert Haas wrote:

I'd be wary of showing a desired value unless it's highly likely to
be accurate.

The desired value is accurately estimated based on (a) the total
number of exact/lossy pages stored in the TIDBitmap and (b) the
following equation in tbm_create(), except for the GIN case where
lossy pages are added to the TIDBitmap by tbm_add_page().

I've found there is another risk of overestimating the desired memory space
for a BitmapAnded TIDBitmap. I'm inclined to get rid of the estimation
functionality from the patch completely, and leave it for future work.
Attached is a new version of the patch, which shows only fetch block
information and memory usage information. I'll add this to the upcoming CF.

Thanks,

Best regards,
Etsuro Fujita

Attachments:

explain-bitmapscan-20131227.patchapplication/octet-stream; name=explain-bitmapscan-20131227.patchDownload
*** 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 */
#13Robert Haas
robertmhaas@gmail.com
In reply to: Etsuro Fujita (#1)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On Fri, Dec 27, 2013 at 1:47 AM, Etsuro Fujita
<fujita.etsuro@lab.ntt.co.jp> wrote:

I wrote:

Robert Haas wrote:

I'd be wary of showing a desired value unless it's highly likely to
be accurate.

The desired value is accurately estimated based on (a) the total
number of exact/lossy pages stored in the TIDBitmap and (b) the
following equation in tbm_create(), except for the GIN case where
lossy pages are added to the TIDBitmap by tbm_add_page().

I've found there is another risk of overestimating the desired memory space
for a BitmapAnded TIDBitmap. I'm inclined to get rid of the estimation
functionality from the patch completely, and leave it for future work.
Attached is a new version of the patch, which shows only fetch block
information and memory usage information. I'll add this to the upcoming CF.

I spent some time looking at this tonight. I don't think the value
that is displayed for the bitmap memory tracking will be accurate in
complex cases. The bitmap heap scan may sit on top of one or more
bitmap-and or bitmap-or nodes. When a bitmap-and operation happens,
one of the two bitmaps being combined will be thrown out and the
number of entries in the other map will, perhaps, be decreased. The
peak memory usage for the surviving bitmap will be reflected in the
number displayed for the bitmap heap scan, but the peak memory usage
for the discarded bitmap will not. This is wholly arbitrary because
both bitmaps existed at the same time, side by side, and which one we
keep and which one we throw out is essentially random.

I think we could report the results in a more principled way if we
reported the value for each bitmap *index* scan node rather than each
bitmap *heap* scan node. However, I'm not sure it's really worth it.
I think what people really care about is knowing whether the bitmap
lossified or not, and generally how much got lossified. The counts of
exact and lossy pages are sufficient for that, without anything
additional - so I'm inclined to think that the best course of action
might be to remove from the patch everything that's concerned with
trying to measure memory usage and just keep the exact/lossy page
counts.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Andres Freund
andres@2ndquadrant.com
In reply to: Robert Haas (#13)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On 2014-01-01 21:15:46 -0500, Robert Haas wrote:

[ sensible reasoning ] However, I'm not sure it's really worth it.
I think what people really care about is knowing whether the bitmap
lossified or not, and generally how much got lossified. The counts of
exact and lossy pages are sufficient for that, without anything
additional

Showing the amount of memory currently required could tell you how soon
accurate bitmap scans will turn into lossy scans though. Which is not a
bad thing to know, some kinds of scans (e.g. tsearch over expression
indexes, postgis) can get ridiculously slow once lossy.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#14)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On Thu, Jan 2, 2014 at 4:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:

On 2014-01-01 21:15:46 -0500, Robert Haas wrote:

[ sensible reasoning ] However, I'm not sure it's really worth it.
I think what people really care about is knowing whether the bitmap
lossified or not, and generally how much got lossified. The counts of
exact and lossy pages are sufficient for that, without anything
additional

Showing the amount of memory currently required could tell you how soon
accurate bitmap scans will turn into lossy scans though. Which is not a
bad thing to know, some kinds of scans (e.g. tsearch over expression
indexes, postgis) can get ridiculously slow once lossy.

Hmm, interesting. I have not encountered that myself. If we want
that, I'm tempted to think that we should display statistics for each
bitmap index scan - but I'd be somewhat inclined to see if we could
get by with the values that are already stored in a TIDBitmap rather
than adding new ones - e.g. show npages (the number of exact entries),
nchunks (the number of lossy entries), and maxentries. From that, you
can work out the percentage of available entries that were actually
used. The only thing that's a bit annoying about that is that we'd
probably have to copy those values out of the tid bitmap and into an
executor state node, because the tid bitmap will subsequently get
modified destructively. But I think that's probably OK.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Robert Haas (#13)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

Robert Haas wrote:

I spent some time looking at this tonight. I don't think the value that
is displayed for the bitmap memory tracking will be accurate in complex
cases. The bitmap heap scan may sit on top of one or more bitmap-and or
bitmap-or nodes. When a bitmap-and operation happens, one of the two
bitmaps being combined will be thrown out and the number of entries in the
other map will, perhaps, be decreased. The peak memory usage for the
surviving bitmap will be reflected in the number displayed for the bitmap
heap scan, but the peak memory usage for the discarded bitmap will not.
This is wholly arbitrary because both bitmaps existed at the same time,
side by side, and which one we keep and which one we throw out is

essentially

random.

Thank you for taking time to look at this patch. The peak memory usage for
the discarded bitmap *can* be reflected in the number displayed for the
bitmap heap scan by the following code in tbm_union() or tbm_intersect():

  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;
***************
  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;
***************

Sorry for the delay.

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Robert Haas
robertmhaas@gmail.com
In reply to: Etsuro Fujita (#1)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On Mon, Jan 6, 2014 at 9:40 PM, Etsuro Fujita
<fujita.etsuro@lab.ntt.co.jp> wrote:

Robert Haas wrote:

I spent some time looking at this tonight. I don't think the value that
is displayed for the bitmap memory tracking will be accurate in complex
cases. The bitmap heap scan may sit on top of one or more bitmap-and or
bitmap-or nodes. When a bitmap-and operation happens, one of the two
bitmaps being combined will be thrown out and the number of entries in the
other map will, perhaps, be decreased. The peak memory usage for the
surviving bitmap will be reflected in the number displayed for the bitmap
heap scan, but the peak memory usage for the discarded bitmap will not.
This is wholly arbitrary because both bitmaps existed at the same time,
side by side, and which one we keep and which one we throw out is

essentially

random.

Thank you for taking time to look at this patch. The peak memory usage for
the discarded bitmap *can* be reflected in the number displayed for the
bitmap heap scan by the following code in tbm_union() or tbm_intersect():

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;
***************
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;
***************

Sorry for the delay.

Hmm, fair point. But I'm still not convinced that we really need to
add extra accounting for this. What's wrong with just reporting the
number of exact and lossy pages?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Robert Haas (#17)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

Robert Haas wrote:

On Mon, Jan 6, 2014 at 9:40 PM, Etsuro Fujita

<fujita.etsuro@lab.ntt.co.jp>

wrote:

Thank you for taking time to look at this patch. The peak memory
usage for the discarded bitmap *can* be reflected in the number
displayed for the bitmap heap scan by the following code in tbm_union()

or tbm_intersect():

Hmm, fair point. But I'm still not convinced that we really need to add
extra accounting for this. What's wrong with just reporting the number
of exact and lossy pages?

No. I intended to show the desired memory space for a TIDBitmap rather than
the peak memory usage for that TIDBitmap. And I thought it'd be better for
the latter to be displayed as additional information. However, I've removed
the functionality for showing the desired memory space due to technical
problems. Now I should probably remove the functionality for showing the
peak memory usage too.

Yes, as Andres mentioned, showing the peak memory usage is not a bad idea, I
think. But I start to think it's not necessarily worth complicating the
code ...

If there are no objections of others, I'll remove extra accounting for
showing the peak memory usage.

Thanks,

Best regards,
Etsuro Fujita

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Etsuro Fujita
fujita.etsuro@lab.ntt.co.jp
In reply to: Etsuro Fujita (#18)
1 attachment(s)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

I wrote:

Robert Haas wrote:

Hmm, fair point. But I'm still not convinced that we really need to
add extra accounting for this. What's wrong with just reporting the
number of exact and lossy pages?

No. I intended to show the desired memory space for a TIDBitmap rather
than the peak memory usage for that TIDBitmap. And I thought it'd be

better

for the latter to be displayed as additional information. However, I've
removed the functionality for showing the desired memory space due to
technical problems. Now I should probably remove the functionality for
showing the peak memory usage too.

Yes, as Andres mentioned, showing the peak memory usage is not a bad idea,
I think. But I start to think it's not necessarily worth complicating the
code ...

If there are no objections of others, I'll remove extra accounting for
showing the peak memory usage.

Done. Please find attached a patch.

Thanks,

Best regards,
Etsuro Fujita

Attachments:

explain-bitmapscan-20140110.patchapplication/octet-stream; name=explain-bitmapscan-20140110.patchDownload
*** a/src/backend/commands/explain.c
--- b/src/backend/commands/explain.c
***************
*** 85,90 **** static void show_sort_group_keys(PlanState *planstate, const char *qlabel,
--- 85,92 ----
  					 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);
***************
*** 1250,1256 **** 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:
--- 1252,1264 ----
  			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:
***************
*** 1879,1884 **** show_hash_info(HashState *hashstate, ExplainState *es)
--- 1887,1915 ----
  }
  
  /*
+  * If it's EXPLAIN ANALYZE, show exact/lossy pages for a BitmapHeapScan node
+  */
+ static void
+ show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
+ {
+ 	if (es->format != EXPLAIN_FORMAT_TEXT)
+ 	{
+ 		ExplainPropertyLong("Exact Heap Blocks", planstate->exact_pages, es);
+ 		ExplainPropertyLong("Lossy Heap Blocks", planstate->lossy_pages, es);
+ 	}
+ 	else
+ 	{
+ 		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');
+ 	}
+ }
+ 
+ /*
   * 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
***************
*** 170,175 **** BitmapHeapNext(BitmapHeapScanState *node)
--- 170,180 ----
  			 */
  			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)
--- 558,565 ----
  	scanstate->tbm = NULL;
  	scanstate->tbmiterator = NULL;
  	scanstate->tbmres = NULL;
+ 	scanstate->exact_pages = 0;
+ 	scanstate->lossy_pages = 0;
  	scanstate->prefetch_iterator = NULL;
  	scanstate->prefetch_pages = 0;
  	scanstate->prefetch_target = 0;
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 1338,1343 **** typedef struct BitmapIndexScanState
--- 1338,1345 ----
   *		tbm				   bitmap obtained from child index scan(s)
   *		tbmiterator		   iterator for scanning current pages
   *		tbmres			   current-page data
+  *		exact_pages		   total number of exact pages retrieved
+  *		lossy_pages		   total number of lossy pages retrieved
   *		prefetch_iterator  iterator for prefetching ahead of current page
   *		prefetch_pages	   # pages prefetch iterator is ahead of current
   *		prefetch_target    target prefetch distance
***************
*** 1350,1355 **** typedef struct BitmapHeapScanState
--- 1352,1359 ----
  	TIDBitmap  *tbm;
  	TBMIterator *tbmiterator;
  	TBMIterateResult *tbmres;
+ 	long		exact_pages;
+ 	long		lossy_pages;
  	TBMIterator *prefetch_iterator;
  	int			prefetch_pages;
  	int			prefetch_target;
#20Robert Haas
robertmhaas@gmail.com
In reply to: Etsuro Fujita (#1)
Re: Show lossy heap block info in EXPLAIN ANALYZE for bitmap heap scan

On Thu, Jan 9, 2014 at 10:57 PM, Etsuro Fujita
<fujita.etsuro@lab.ntt.co.jp> wrote:

I wrote:

Robert Haas wrote:

Hmm, fair point. But I'm still not convinced that we really need to
add extra accounting for this. What's wrong with just reporting the
number of exact and lossy pages?

No. I intended to show the desired memory space for a TIDBitmap rather
than the peak memory usage for that TIDBitmap. And I thought it'd be

better

for the latter to be displayed as additional information. However, I've
removed the functionality for showing the desired memory space due to
technical problems. Now I should probably remove the functionality for
showing the peak memory usage too.

Yes, as Andres mentioned, showing the peak memory usage is not a bad idea,
I think. But I start to think it's not necessarily worth complicating the
code ...

If there are no objections of others, I'll remove extra accounting for
showing the peak memory usage.

Done. Please find attached a patch.

Looks good to me, so committed.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers