Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions src/backend/commands/explain.c
Original file line number Diff line number Diff line change
Expand Up @@ -3924,26 +3924,45 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es)
static void
show_tidbitmap_info(BitmapHeapScanState *planstate, ExplainState *es)
{
uint64 exact_pages;
uint64 lossy_pages;

if (!es->analyze)
return;

/* Start with leader's stats */
exact_pages = planstate->stats.exact_pages;
lossy_pages = planstate->stats.lossy_pages;

/* Accumulate worker stats into node-level totals */
if (planstate->sinstrument != NULL)
{
for (int n = 0; n < planstate->sinstrument->num_workers; n++)
{
BitmapHeapScanInstrumentation *si = &planstate->sinstrument->sinstrument[n];

exact_pages += si->exact_pages;
lossy_pages += si->lossy_pages;
}
}

if (es->format != EXPLAIN_FORMAT_TEXT)
{
ExplainPropertyUInteger("Exact Heap Blocks", NULL,
planstate->stats.exact_pages, es);
exact_pages, es);
ExplainPropertyUInteger("Lossy Heap Blocks", NULL,
planstate->stats.lossy_pages, es);
lossy_pages, es);
}
else
{
if (planstate->stats.exact_pages > 0 || planstate->stats.lossy_pages > 0)
if (exact_pages > 0 || lossy_pages > 0)
{
ExplainIndentText(es);
appendStringInfoString(es->str, "Heap Blocks:");
if (planstate->stats.exact_pages > 0)
appendStringInfo(es->str, " exact=" UINT64_FORMAT, planstate->stats.exact_pages);
if (planstate->stats.lossy_pages > 0)
appendStringInfo(es->str, " lossy=" UINT64_FORMAT, planstate->stats.lossy_pages);
if (exact_pages > 0)
appendStringInfo(es->str, " exact=" UINT64_FORMAT, exact_pages);
if (lossy_pages > 0)
appendStringInfo(es->str, " lossy=" UINT64_FORMAT, lossy_pages);
appendStringInfoChar(es->str, '\n');
}
}
Expand Down
67 changes: 67 additions & 0 deletions src/test/regress/expected/explain.out
Original file line number Diff line number Diff line change
Expand Up @@ -822,3 +822,70 @@ select explain_filter('explain (analyze,buffers off,costs off) select sum(n) ove
(9 rows)

reset work_mem;
-- Test parallel bitmap heap scan reports per-worker heap block stats.
CREATE FUNCTION check_parallel_bitmap_heap_scan() RETURNS boolean AS $$
DECLARE
plan_json json;
node json;
BEGIN
SET LOCAL enable_seqscan = off;
SET LOCAL enable_indexscan = off;
SET LOCAL parallel_setup_cost = 0;
SET LOCAL parallel_tuple_cost = 0;
SET LOCAL min_parallel_table_scan_size = 0;
SET LOCAL min_parallel_index_scan_size = 0;
SET LOCAL max_parallel_workers_per_gather = 2;
SET LOCAL parallel_leader_participation = off;

EXECUTE 'EXPLAIN (ANALYZE, BUFFERS, COSTS OFF, FORMAT JSON)
SELECT count(*) FROM tenk1 WHERE hundred > 1' INTO plan_json;

node := plan_json->0->'Plan';
WHILE node->'Plans' IS NOT NULL AND node->>'Node Type' != 'Bitmap Heap Scan' LOOP
node := node->'Plans'->0;
END LOOP;

RETURN COALESCE((node->>'Exact Heap Blocks')::int, 0) > 0;
END;
$$ LANGUAGE plpgsql;
SELECT check_parallel_bitmap_heap_scan() AS parallel_bitmap_instrumentation;
parallel_bitmap_instrumentation
---------------------------------
t
(1 row)

DROP FUNCTION check_parallel_bitmap_heap_scan;
-- Test parallel index-only scan reports per-worker index search stats.
CREATE FUNCTION check_parallel_indexonly_scan() RETURNS boolean AS $$
DECLARE
plan_json json;
node json;
BEGIN
SET LOCAL enable_seqscan = off;
SET LOCAL enable_bitmapscan = off;
SET LOCAL parallel_setup_cost = 0;
SET LOCAL parallel_tuple_cost = 0;
SET LOCAL min_parallel_index_scan_size = 0;
SET LOCAL min_parallel_table_scan_size = 0;
SET LOCAL max_parallel_workers_per_gather = 2;
SET LOCAL parallel_leader_participation = off;

EXECUTE 'EXPLAIN (ANALYZE, BUFFERS, COSTS OFF, FORMAT JSON)
SELECT count(*) FROM tenk1 WHERE thousand > 95' INTO plan_json;

-- Drill down to the Index Only Scan node
node := plan_json->0->'Plan';
WHILE node->'Plans' IS NOT NULL AND node->>'Node Type' != 'Index Only Scan' LOOP
node := node->'Plans'->0;
END LOOP;

RETURN COALESCE((node->>'Index Searches')::int, 0) > 0;
END;
$$ LANGUAGE plpgsql;
SELECT check_parallel_indexonly_scan() AS parallel_indexonly_instrumentation;
parallel_indexonly_instrumentation
------------------------------------
t
(1 row)

DROP FUNCTION check_parallel_indexonly_scan;
63 changes: 63 additions & 0 deletions src/test/regress/sql/explain.sql
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,66 @@ select explain_filter('explain (analyze,buffers off,costs off) select sum(n) ove
-- Test tuplestore storage usage in Window aggregate (memory and disk case, final result is disk)
select explain_filter('explain (analyze,buffers off,costs off) select sum(n) over(partition by m) from (SELECT n < 3 as m, n from generate_series(1,2500) a(n))');
reset work_mem;

-- Test parallel bitmap heap scan reports per-worker heap block stats.
CREATE FUNCTION check_parallel_bitmap_heap_scan() RETURNS boolean AS $$
DECLARE
plan_json json;
node json;
BEGIN
SET LOCAL enable_seqscan = off;
SET LOCAL enable_indexscan = off;
SET LOCAL parallel_setup_cost = 0;
SET LOCAL parallel_tuple_cost = 0;
SET LOCAL min_parallel_table_scan_size = 0;
SET LOCAL min_parallel_index_scan_size = 0;
SET LOCAL max_parallel_workers_per_gather = 2;
SET LOCAL parallel_leader_participation = off;

EXECUTE 'EXPLAIN (ANALYZE, BUFFERS, COSTS OFF, FORMAT JSON)
SELECT count(*) FROM tenk1 WHERE hundred > 1' INTO plan_json;

node := plan_json->0->'Plan';
WHILE node->'Plans' IS NOT NULL AND node->>'Node Type' != 'Bitmap Heap Scan' LOOP
node := node->'Plans'->0;
END LOOP;

RETURN COALESCE((node->>'Exact Heap Blocks')::int, 0) > 0;
END;
$$ LANGUAGE plpgsql;

SELECT check_parallel_bitmap_heap_scan() AS parallel_bitmap_instrumentation;

DROP FUNCTION check_parallel_bitmap_heap_scan;

-- Test parallel index-only scan reports per-worker index search stats.
CREATE FUNCTION check_parallel_indexonly_scan() RETURNS boolean AS $$
DECLARE
plan_json json;
node json;
BEGIN
SET LOCAL enable_seqscan = off;
SET LOCAL enable_bitmapscan = off;
SET LOCAL parallel_setup_cost = 0;
SET LOCAL parallel_tuple_cost = 0;
SET LOCAL min_parallel_index_scan_size = 0;
SET LOCAL min_parallel_table_scan_size = 0;
SET LOCAL max_parallel_workers_per_gather = 2;
SET LOCAL parallel_leader_participation = off;

EXECUTE 'EXPLAIN (ANALYZE, BUFFERS, COSTS OFF, FORMAT JSON)
SELECT count(*) FROM tenk1 WHERE thousand > 95' INTO plan_json;

-- Drill down to the Index Only Scan node
node := plan_json->0->'Plan';
WHILE node->'Plans' IS NOT NULL AND node->>'Node Type' != 'Index Only Scan' LOOP
node := node->'Plans'->0;
END LOOP;

RETURN COALESCE((node->>'Index Searches')::int, 0) > 0;
END;
$$ LANGUAGE plpgsql;

SELECT check_parallel_indexonly_scan() AS parallel_indexonly_instrumentation;

DROP FUNCTION check_parallel_indexonly_scan;