mirror of https://github.com/postgres/postgres
Add memory/disk usage for Window aggregate nodes in EXPLAIN.
This commit is similar to 1eff8279d
and expands the idea to Window
aggregate nodes so that users can know how much memory or disk the
tuplestore used.
This commit uses newly introduced tuplestore_get_stats() to inquire this
information and add some additional output in EXPLAIN ANALYZE to
display the information for the Window aggregate node.
Reviewed-by: David Rowley, Ashutosh Bapat, Maxim Orlov, Jian He
Discussion: https://postgr.es/m/20240706.202254.89740021795421286.ishii%40postgresql.org
This commit is contained in:
parent
1bbf1e2f1a
commit
95d6e9af07
|
@ -120,6 +120,7 @@ static void show_sort_group_keys(PlanState *planstate, const char *qlabel,
|
|||
List *ancestors, ExplainState *es);
|
||||
static void show_sortorder_options(StringInfo buf, Node *sortexpr,
|
||||
Oid sortOperator, Oid collation, bool nullsFirst);
|
||||
static void show_storage_info(Tuplestorestate *tupstore, ExplainState *es);
|
||||
static void show_tablesample(TableSampleClause *tsc, PlanState *planstate,
|
||||
List *ancestors, ExplainState *es);
|
||||
static void show_sort_info(SortState *sortstate, ExplainState *es);
|
||||
|
@ -127,6 +128,7 @@ static void show_incremental_sort_info(IncrementalSortState *incrsortstate,
|
|||
ExplainState *es);
|
||||
static void show_hash_info(HashState *hashstate, ExplainState *es);
|
||||
static void show_material_info(MaterialState *mstate, ExplainState *es);
|
||||
static void show_windowagg_info(WindowAggState *winstate, ExplainState *es);
|
||||
static void show_memoize_info(MemoizeState *mstate, List *ancestors,
|
||||
ExplainState *es);
|
||||
static void show_hashagg_info(AggState *aggstate, ExplainState *es);
|
||||
|
@ -2231,6 +2233,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
|
|||
planstate, es);
|
||||
show_upper_qual(((WindowAgg *) plan)->runConditionOrig,
|
||||
"Run Condition", planstate, ancestors, es);
|
||||
show_windowagg_info(castNode(WindowAggState, planstate), es);
|
||||
break;
|
||||
case T_Group:
|
||||
show_group_keys(castNode(GroupState, planstate), ancestors, es);
|
||||
|
@ -2894,6 +2897,34 @@ show_sortorder_options(StringInfo buf, Node *sortexpr,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Show information on storage method and maximum memory/disk space used.
|
||||
*/
|
||||
static void
|
||||
show_storage_info(Tuplestorestate *tupstore, ExplainState *es)
|
||||
{
|
||||
char *maxStorageType;
|
||||
int64 maxSpaceUsed,
|
||||
maxSpaceUsedKB;
|
||||
|
||||
tuplestore_get_stats(tupstore, &maxStorageType, &maxSpaceUsed);
|
||||
maxSpaceUsedKB = BYTES_TO_KILOBYTES(maxSpaceUsed);
|
||||
|
||||
if (es->format != EXPLAIN_FORMAT_TEXT)
|
||||
{
|
||||
ExplainPropertyText("Storage", maxStorageType, es);
|
||||
ExplainPropertyInteger("Maximum Storage", "kB", maxSpaceUsedKB, es);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplainIndentText(es);
|
||||
appendStringInfo(es->str,
|
||||
"Storage: %s Maximum Storage: " INT64_FORMAT "kB\n",
|
||||
maxStorageType,
|
||||
maxSpaceUsedKB);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Show TABLESAMPLE properties
|
||||
*/
|
||||
|
@ -3350,9 +3381,6 @@ static void
|
|||
show_material_info(MaterialState *mstate, ExplainState *es)
|
||||
{
|
||||
Tuplestorestate *tupstore = mstate->tuplestorestate;
|
||||
char *maxStorageType;
|
||||
int64 maxSpaceUsed,
|
||||
maxSpaceUsedKB;
|
||||
|
||||
/*
|
||||
* Nothing to show if ANALYZE option wasn't used or if execution didn't
|
||||
|
@ -3361,22 +3389,26 @@ show_material_info(MaterialState *mstate, ExplainState *es)
|
|||
if (!es->analyze || tupstore == NULL)
|
||||
return;
|
||||
|
||||
tuplestore_get_stats(tupstore, &maxStorageType, &maxSpaceUsed);
|
||||
maxSpaceUsedKB = BYTES_TO_KILOBYTES(maxSpaceUsed);
|
||||
show_storage_info(tupstore, es);
|
||||
}
|
||||
|
||||
if (es->format != EXPLAIN_FORMAT_TEXT)
|
||||
{
|
||||
ExplainPropertyText("Storage", maxStorageType, es);
|
||||
ExplainPropertyInteger("Maximum Storage", "kB", maxSpaceUsedKB, es);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplainIndentText(es);
|
||||
appendStringInfo(es->str,
|
||||
"Storage: %s Maximum Storage: " INT64_FORMAT "kB\n",
|
||||
maxStorageType,
|
||||
maxSpaceUsedKB);
|
||||
}
|
||||
/*
|
||||
* Show information on WindowAgg node, storage method and maximum memory/disk
|
||||
* space used.
|
||||
*/
|
||||
static void
|
||||
show_windowagg_info(WindowAggState *winstate, ExplainState *es)
|
||||
{
|
||||
Tuplestorestate *tupstore = winstate->buffer;
|
||||
|
||||
/*
|
||||
* Nothing to show if ANALYZE option wasn't used or if execution didn't
|
||||
* get as far as creating the tuplestore.
|
||||
*/
|
||||
if (!es->analyze || tupstore == NULL)
|
||||
return;
|
||||
|
||||
show_storage_info(tupstore, es);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -691,3 +691,41 @@ select explain_filter('explain (analyze,serialize) create temp table explain_tem
|
|||
Execution Time: N.N ms
|
||||
(4 rows)
|
||||
|
||||
-- Test tuplestore storage usage in Window aggregate (memory case)
|
||||
select explain_filter('explain (analyze,costs off) select sum(n) over() from generate_series(1,10) a(n)');
|
||||
explain_filter
|
||||
--------------------------------------------------------------------------------
|
||||
WindowAgg (actual time=N.N..N.N rows=N loops=N)
|
||||
Storage: Memory Maximum Storage: NkB
|
||||
-> Function Scan on generate_series a (actual time=N.N..N.N rows=N loops=N)
|
||||
Planning Time: N.N ms
|
||||
Execution Time: N.N ms
|
||||
(5 rows)
|
||||
|
||||
-- Test tuplestore storage usage in Window aggregate (disk case)
|
||||
set work_mem to 64;
|
||||
select explain_filter('explain (analyze,costs off) select sum(n) over() from generate_series(1,2000) a(n)');
|
||||
explain_filter
|
||||
--------------------------------------------------------------------------------
|
||||
WindowAgg (actual time=N.N..N.N rows=N loops=N)
|
||||
Storage: Disk Maximum Storage: NkB
|
||||
-> Function Scan on generate_series a (actual time=N.N..N.N rows=N loops=N)
|
||||
Planning Time: N.N ms
|
||||
Execution Time: N.N ms
|
||||
(5 rows)
|
||||
|
||||
-- Test tuplestore storage usage in Window aggregate (memory and disk case, final result is disk)
|
||||
select explain_filter('explain (analyze,costs off) select sum(n) over(partition by m) from (SELECT n < 3 as m, n from generate_series(1,2000) a(n))');
|
||||
explain_filter
|
||||
--------------------------------------------------------------------------------------
|
||||
WindowAgg (actual time=N.N..N.N rows=N loops=N)
|
||||
Storage: Disk Maximum Storage: NkB
|
||||
-> Sort (actual time=N.N..N.N rows=N loops=N)
|
||||
Sort Key: ((a.n < N))
|
||||
Sort Method: external merge Disk: NkB
|
||||
-> Function Scan on generate_series a (actual time=N.N..N.N rows=N loops=N)
|
||||
Planning Time: N.N ms
|
||||
Execution Time: N.N ms
|
||||
(8 rows)
|
||||
|
||||
reset work_mem;
|
||||
|
|
|
@ -169,3 +169,12 @@ select explain_filter('explain (analyze,serialize text,buffers,timing off) selec
|
|||
select explain_filter('explain (analyze,serialize binary,buffers,timing) select * from int8_tbl i8');
|
||||
-- this tests an edge case where we have no data to return
|
||||
select explain_filter('explain (analyze,serialize) create temp table explain_temp as select * from int8_tbl i8');
|
||||
|
||||
-- Test tuplestore storage usage in Window aggregate (memory case)
|
||||
select explain_filter('explain (analyze,costs off) select sum(n) over() from generate_series(1,10) a(n)');
|
||||
-- Test tuplestore storage usage in Window aggregate (disk case)
|
||||
set work_mem to 64;
|
||||
select explain_filter('explain (analyze,costs off) select sum(n) over() from generate_series(1,2000) a(n)');
|
||||
-- Test tuplestore storage usage in Window aggregate (memory and disk case, final result is disk)
|
||||
select explain_filter('explain (analyze,costs off) select sum(n) over(partition by m) from (SELECT n < 3 as m, n from generate_series(1,2000) a(n))');
|
||||
reset work_mem;
|
||||
|
|
Loading…
Reference in New Issue