Hello, Le jeu. 5 sept. 2024 à 08:19, Guillaume Lelarge <guilla...@lelarge.info> a écrit :
> Le jeu. 5 sept. 2024 à 07:36, Bertrand Drouvot < > bertranddrouvot...@gmail.com> a écrit : > >> Hi, >> >> On Wed, Sep 04, 2024 at 04:37:19PM +0200, Guillaume Lelarge wrote: >> > Hi, >> > >> > Le mer. 4 sept. 2024 à 16:18, Bertrand Drouvot < >> bertranddrouvot...@gmail.com> >> > a écrit : >> > > What about adding a comment instead of this extra check? >> > > >> > > >> > Done too in v3. >> >> Thanks! >> >> 1 === >> >> + /* >> + * Don't check counts.parallelnumscans because counts.numscans >> includes >> + * counts.parallelnumscans >> + */ >> >> "." is missing at the end of the comment. >> >> > Fixed in v4. > > >> 2 === >> >> - if (t > tabentry->lastscan) >> + if (t > tabentry->lastscan && lstats->counts.numscans) >> >> The extra check on lstats->counts.numscans is not needed as it's already >> done >> a few lines before. >> >> > Fixed in v4. > > >> 3 === >> >> + if (t > tabentry->parallellastscan && >> lstats->counts.parallelnumscans) >> >> This one makes sense. >> >> And now I'm wondering if the extra comment added in v3 is really worth it >> (and >> does not sound confusing)? I mean, the parallel check is done once we >> passe >> the initial test on counts.numscans. I think the code is clear enough >> without >> this extra comment, thoughts? >> >> > I'm not sure I understand you here. I kinda like the extra comment though. > > >> 4 === >> >> What about adding a few tests? or do you want to wait a bit more to see >> if " >> there's an agreement on this patch" (as you stated at the start of this >> thread). >> >> > Guess I can start working on that now. It will take some time as I've > never done it before. Good thing I added the patch on the November commit > fest :) > > Finally found some time to work on this. Tests added on v5 patch (attached). Regards. -- Guillaume.
From 92474720b3178f74517958fededcf6797de58552 Mon Sep 17 00:00:00 2001 From: Guillaume Lelarge <guillaume.lela...@dalibo.com> Date: Sun, 6 Oct 2024 21:50:17 +0200 Subject: [PATCH v5] Add parallel columns for pg_stat_all_tables,indexes pg_stat_all_tables gets 4 new columns: parallel_seq_scan, last_parallel_seq_scan, parallel_idx_scan, last_parallel_idx_scan. pg_stat_all_indexes gets 2 new columns: parallel_idx_scan, last_parallel_idx_scan. --- doc/src/sgml/monitoring.sgml | 69 ++++++- src/backend/access/brin/brin.c | 2 +- src/backend/access/gin/ginscan.c | 2 +- src/backend/access/gist/gistget.c | 4 +- src/backend/access/hash/hashsearch.c | 2 +- src/backend/access/heap/heapam.c | 2 +- src/backend/access/nbtree/nbtsearch.c | 12 +- src/backend/access/spgist/spgscan.c | 2 +- src/backend/catalog/system_views.sql | 6 + src/backend/utils/activity/pgstat_relation.c | 8 + src/backend/utils/adt/pgstatfuncs.c | 6 + src/include/catalog/pg_proc.dat | 8 + src/include/pgstat.h | 17 +- src/test/regress/expected/rules.out | 18 ++ src/test/regress/expected/stats.out | 194 +++++++++++++++++++ src/test/regress/sql/stats.sql | 92 +++++++++ 16 files changed, 421 insertions(+), 23 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 331315f8d3..aeaabb0ffe 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -3803,7 +3803,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>seq_scan</structfield> <type>bigint</type> </para> <para> - Number of sequential scans initiated on this table + Number of sequential scans (including parallel ones) initiated on this table </para></entry> </row> @@ -3812,7 +3812,26 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>last_seq_scan</structfield> <type>timestamp with time zone</type> </para> <para> - The time of the last sequential scan on this table, based on the + The time of the last sequential scan (including parallel ones) on this table, based on the + most recent transaction stop time + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>parallel_seq_scan</structfield> <type>bigint</type> + </para> + <para> + Number of parallel sequential scans initiated on this table + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_parallel_seq_scan</structfield> <type>timestamp with time zone</type> + </para> + <para> + The time of the last parallel sequential scan on this table, based on the most recent transaction stop time </para></entry> </row> @@ -3831,7 +3850,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>idx_scan</structfield> <type>bigint</type> </para> <para> - Number of index scans initiated on this table + Number of index scans (including parallel ones) initiated on this table </para></entry> </row> @@ -3840,7 +3859,26 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>last_idx_scan</structfield> <type>timestamp with time zone</type> </para> <para> - The time of the last index scan on this table, based on the + The time of the last index scan (including parallel ones) on this table, based on the + most recent transaction stop time + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>parallel_idx_scan</structfield> <type>bigint</type> + </para> + <para> + Number of parallel index scans initiated on this table + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_parallel_idx_scan</structfield> <type>timestamp with time zone</type> + </para> + <para> + The time of the last parallel index scan on this table, based on the most recent transaction stop time </para></entry> </row> @@ -4110,7 +4148,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>idx_scan</structfield> <type>bigint</type> </para> <para> - Number of index scans initiated on this index + Number of index scans (including parallel ones) initiated on this index </para></entry> </row> @@ -4119,7 +4157,26 @@ description | Waiting for a newly initialized WAL file to reach durable storage <structfield>last_idx_scan</structfield> <type>timestamp with time zone</type> </para> <para> - The time of the last scan on this index, based on the + The time of the last scan on this index(including parallel ones), based + on the most recent transaction stop time + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>parallel_idx_scan</structfield> <type>bigint</type> + </para> + <para> + Number of parallel index scans initiated on this index + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>last_parallel_idx_scan</structfield> <type>timestamp with time zone</type> + </para> + <para> + The time of the last parallel scan on this index, based on the most recent transaction stop time </para></entry> </row> diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index c0b978119a..0fffa67301 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -584,7 +584,7 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) opaque = (BrinOpaque *) scan->opaque; bdesc = opaque->bo_bdesc; - pgstat_count_index_scan(idxRel); + pgstat_count_index_scan(idxRel, false); /* * We need to know the size of the table so that we know how long to diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index f2fd62afbb..d2001d6054 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -435,7 +435,7 @@ ginNewScanKey(IndexScanDesc scan) MemoryContextSwitchTo(oldCtx); - pgstat_count_index_scan(scan->indexRelation); + pgstat_count_index_scan(scan->indexRelation, false); } void diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c index b35b8a9757..7e89382ce5 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -624,7 +624,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir) /* Begin the scan by processing the root page */ GISTSearchItem fakeItem; - pgstat_count_index_scan(scan->indexRelation); + pgstat_count_index_scan(scan->indexRelation, false); so->firstCall = false; so->curPageData = so->nPageData = 0; @@ -749,7 +749,7 @@ gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm) if (!so->qual_ok) return 0; - pgstat_count_index_scan(scan->indexRelation); + pgstat_count_index_scan(scan->indexRelation, false); /* Begin the scan by processing the root page */ so->curPageData = so->nPageData = 0; diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c index 0d99d6abc8..a63edc8372 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -297,7 +297,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) HashPageOpaque opaque; HashScanPosItem *currItem; - pgstat_count_index_scan(rel); + pgstat_count_index_scan(rel, false); /* * We do not support hash scans with no index qualification, because we diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index da5e656a08..099b08242f 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -400,7 +400,7 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock) * and for sample scans we update stats for tuple fetches). */ if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN) - pgstat_count_heap_scan(scan->rs_base.rs_rd); + pgstat_count_heap_scan(scan->rs_base.rs_rd, (scan->rs_base.rs_parallel != NULL)); } /* diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index fff7c89ead..8115b0fa2d 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -912,6 +912,12 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) return false; } + /* + * Count an indexscan for stats, now that we know that we'll call + * _bt_search/_bt_endpoint below + */ + pgstat_count_index_scan(rel, (scan->parallel_scan != NULL)); + /* * For parallel scans, get the starting page from shared state. If the * scan has not started, proceed to find out first leaf page in the usual @@ -958,12 +964,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) _bt_start_array_keys(scan, dir); } - /* - * Count an indexscan for stats, now that we know that we'll call - * _bt_search/_bt_endpoint below - */ - pgstat_count_index_scan(rel); - /*---------- * Examine the scan keys to discover where we need to start the scan. * diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c index 3017861859..fe3c9979df 100644 --- a/src/backend/access/spgist/spgscan.c +++ b/src/backend/access/spgist/spgscan.c @@ -420,7 +420,7 @@ spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, resetSpGistScanOpaque(so); /* count an indexscan for stats */ - pgstat_count_index_scan(scan->indexRelation); + pgstat_count_index_scan(scan->indexRelation, false); } void diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 3456b821bc..b062af32fb 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -670,9 +670,13 @@ CREATE VIEW pg_stat_all_tables AS C.relname AS relname, pg_stat_get_numscans(C.oid) AS seq_scan, pg_stat_get_lastscan(C.oid) AS last_seq_scan, + pg_stat_get_parallelnumscans(C.oid) AS parallel_seq_scan, + pg_stat_get_parallellastscan(C.oid) AS last_parallel_seq_scan, pg_stat_get_tuples_returned(C.oid) AS seq_tup_read, sum(pg_stat_get_numscans(I.indexrelid))::bigint AS idx_scan, max(pg_stat_get_lastscan(I.indexrelid)) AS last_idx_scan, + sum(pg_stat_get_parallelnumscans(I.indexrelid))::bigint AS parallel_idx_scan, + max(pg_stat_get_parallellastscan(I.indexrelid)) AS last_parallel_idx_scan, sum(pg_stat_get_tuples_fetched(I.indexrelid))::bigint + pg_stat_get_tuples_fetched(C.oid) AS idx_tup_fetch, pg_stat_get_tuples_inserted(C.oid) AS n_tup_ins, @@ -792,6 +796,8 @@ CREATE VIEW pg_stat_all_indexes AS I.relname AS indexrelname, pg_stat_get_numscans(I.oid) AS idx_scan, pg_stat_get_lastscan(I.oid) AS last_idx_scan, + pg_stat_get_parallelnumscans(I.oid) AS parallel_idx_scan, + pg_stat_get_parallellastscan(I.oid) AS last_parallel_idx_scan, pg_stat_get_tuples_returned(I.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(I.oid) AS idx_tup_fetch FROM pg_class C JOIN diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c index 8a3f7d434c..766c56524e 100644 --- a/src/backend/utils/activity/pgstat_relation.c +++ b/src/backend/utils/activity/pgstat_relation.c @@ -829,12 +829,20 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) tabentry = &shtabstats->stats; tabentry->numscans += lstats->counts.numscans; + tabentry->parallelnumscans += lstats->counts.parallelnumscans; + + /* + * Don't check counts.parallelnumscans because counts.numscans includes + * counts.parallelnumscans. + */ if (lstats->counts.numscans) { TimestampTz t = GetCurrentTransactionStopTimestamp(); if (t > tabentry->lastscan) tabentry->lastscan = t; + if (t > tabentry->parallellastscan && lstats->counts.parallelnumscans) + tabentry->parallellastscan = t; } tabentry->tuples_returned += lstats->counts.tuples_returned; tabentry->tuples_fetched += lstats->counts.tuples_fetched; diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index f7b50e0b5a..2bb2e7bdbc 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -82,6 +82,9 @@ PG_STAT_GET_RELENTRY_INT64(mod_since_analyze) /* pg_stat_get_numscans */ PG_STAT_GET_RELENTRY_INT64(numscans) +/* pg_stat_get_parallelnumscans */ +PG_STAT_GET_RELENTRY_INT64(parallelnumscans) + /* pg_stat_get_tuples_deleted */ PG_STAT_GET_RELENTRY_INT64(tuples_deleted) @@ -140,6 +143,9 @@ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time) /* pg_stat_get_lastscan */ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan) +/* pg_stat_get_parallellastscan */ +PG_STAT_GET_RELENTRY_TIMESTAMPTZ(parallellastscan) + Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 77f54a79e6..e92a924dd2 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5443,6 +5443,14 @@ proname => 'pg_stat_get_lastscan', provolatile => 's', proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', prosrc => 'pg_stat_get_lastscan' }, +{ oid => '9000', descr => 'statistics: number of parallel scans done for table/index', + proname => 'pg_stat_get_parallelnumscans', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_parallelnumscans' }, +{ oid => '9001', descr => 'statistics: time of the last parallel scan for table/index', + proname => 'pg_stat_get_parallellastscan', provolatile => 's', proparallel => 'r', + prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_parallellastscan' }, { oid => '1929', descr => 'statistics: number of tuples read by seqscan', proname => 'pg_stat_get_tuples_returned', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index df53fa2d4f..55dbeefd24 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -192,6 +192,7 @@ typedef struct PgStat_BackendSubEntry typedef struct PgStat_TableCounts { PgStat_Counter numscans; + PgStat_Counter parallelnumscans; PgStat_Counter tuples_returned; PgStat_Counter tuples_fetched; @@ -435,6 +436,8 @@ typedef struct PgStat_StatTabEntry { PgStat_Counter numscans; TimestampTz lastscan; + PgStat_Counter parallelnumscans; + TimestampTz parallellastscan; PgStat_Counter tuples_returned; PgStat_Counter tuples_fetched; @@ -642,10 +645,13 @@ extern void pgstat_report_analyze(Relation rel, /* nontransactional event counts are simple enough to inline */ -#define pgstat_count_heap_scan(rel) \ +#define pgstat_count_heap_scan(rel, parallel) \ do { \ - if (pgstat_should_count_relation(rel)) \ + if (pgstat_should_count_relation(rel)) { \ (rel)->pgstat_info->counts.numscans++; \ + if (parallel) \ + (rel)->pgstat_info->counts.parallelnumscans++; \ + } \ } while (0) #define pgstat_count_heap_getnext(rel) \ do { \ @@ -657,10 +663,13 @@ extern void pgstat_report_analyze(Relation rel, if (pgstat_should_count_relation(rel)) \ (rel)->pgstat_info->counts.tuples_fetched++; \ } while (0) -#define pgstat_count_index_scan(rel) \ +#define pgstat_count_index_scan(rel, parallel) \ do { \ - if (pgstat_should_count_relation(rel)) \ + if (pgstat_should_count_relation(rel)) { \ (rel)->pgstat_info->counts.numscans++; \ + if (parallel) \ + (rel)->pgstat_info->counts.parallelnumscans++; \ + } \ } while (0) #define pgstat_count_index_tuples(rel, n) \ do { \ diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 2b47013f11..a8c390fd89 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1772,6 +1772,8 @@ pg_stat_all_indexes| SELECT c.oid AS relid, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_lastscan(i.oid) AS last_idx_scan, + pg_stat_get_parallelnumscans(i.oid) AS parallel_idx_scan, + pg_stat_get_parallellastscan(i.oid) AS last_parallel_idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c @@ -1784,9 +1786,13 @@ pg_stat_all_tables| SELECT c.oid AS relid, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_lastscan(c.oid) AS last_seq_scan, + pg_stat_get_parallelnumscans(c.oid) AS parallel_seq_scan, + pg_stat_get_parallellastscan(c.oid) AS last_parallel_seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, max(pg_stat_get_lastscan(i.indexrelid)) AS last_idx_scan, + (sum(pg_stat_get_parallelnumscans(i.indexrelid)))::bigint AS parallel_idx_scan, + max(pg_stat_get_parallellastscan(i.indexrelid)) AS last_parallel_idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, @@ -2157,6 +2163,8 @@ pg_stat_sys_indexes| SELECT relid, indexrelname, idx_scan, last_idx_scan, + parallel_idx_scan, + last_parallel_idx_scan, idx_tup_read, idx_tup_fetch FROM pg_stat_all_indexes @@ -2166,9 +2174,13 @@ pg_stat_sys_tables| SELECT relid, relname, seq_scan, last_seq_scan, + parallel_seq_scan, + last_parallel_seq_scan, seq_tup_read, idx_scan, last_idx_scan, + parallel_idx_scan, + last_parallel_idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, @@ -2205,6 +2217,8 @@ pg_stat_user_indexes| SELECT relid, indexrelname, idx_scan, last_idx_scan, + parallel_idx_scan, + last_parallel_idx_scan, idx_tup_read, idx_tup_fetch FROM pg_stat_all_indexes @@ -2214,9 +2228,13 @@ pg_stat_user_tables| SELECT relid, relname, seq_scan, last_seq_scan, + parallel_seq_scan, + last_parallel_seq_scan, seq_tup_read, idx_scan, last_idx_scan, + parallel_idx_scan, + last_parallel_idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index 56771f83ed..2fe229dd5a 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -764,6 +764,200 @@ FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; 2 | t | 3 | t (1 row) +----- +-- Test that parallel_seq_scan, last_parallel_seq_scan, parallel_idx_scan, last_parallel_idx_scan are correctly maintained +-- +-- We can't use a temporary table for parallel test. So, perform test using a permanent table, +-- but disable autovacuum on it. That way autovacuum etc won't +-- interfere. To be able to check that timestamps increase, we sleep for 100ms +-- between tests, assuming that there aren't systems with a coarser timestamp +-- granularity. +----- +BEGIN; +CREATE TABLE test_parallel_scan(idx_col int primary key, noidx_col int) WITH (autovacuum_enabled = false); +INSERT INTO test_parallel_scan(idx_col, noidx_col) SELECT i, i FROM generate_series(1, 10_000) i; +COMMIT; +VACUUM ANALYZE test_parallel_scan; +SELECT pg_stat_force_next_flush(); + pg_stat_force_next_flush +-------------------------- + +(1 row) + +SELECT parallel_seq_scan, last_parallel_seq_scan, parallel_idx_scan, last_parallel_idx_scan +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + parallel_seq_scan | last_parallel_seq_scan | parallel_idx_scan | last_parallel_idx_scan +-------------------+------------------------+-------------------+------------------------ + 0 | | 0 | +(1 row) + +-- ensure we start out with exactly one parallel index and parallel sequential scan +BEGIN; +SET LOCAL parallel_setup_cost TO 0; +SET LOCAL min_parallel_table_scan_size TO '100kB'; +SET LOCAL min_parallel_index_scan_size TO '100kB'; +SET LOCAL enable_seqscan TO on; +SET LOCAL enable_indexscan TO on; +SET LOCAL enable_bitmapscan TO off; +SET LOCAL enable_indexonlyscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; + QUERY PLAN +----------------------------------------------------- + Aggregate + -> Gather + Workers Planned: 2 + -> Parallel Seq Scan on test_parallel_scan + Filter: (noidx_col = 1) +(5 rows) + +SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; + count +------- + 1 +(1 row) + +SET LOCAL enable_seqscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; + QUERY PLAN +------------------------------------------------------------------------------------------- + Finalize Aggregate + -> Gather + Workers Planned: 1 + -> Partial Aggregate + -> Parallel Index Scan using test_parallel_scan_pkey on test_parallel_scan + Index Cond: ((idx_col >= 1) AND (idx_col <= 6000)) +(6 rows) + +SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; + count +------- + 6000 +(1 row) + +SELECT pg_stat_force_next_flush(); + pg_stat_force_next_flush +-------------------------- + +(1 row) + +COMMIT; +-- fetch timestamps from before the next test +SELECT parallel_seq_scan, parallel_idx_scan +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + parallel_seq_scan | parallel_idx_scan +-------------------+------------------- + 3 | 2 +(1 row) + +SELECT last_parallel_seq_scan AS test_last_seq, last_parallel_idx_scan AS test_last_idx +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass \gset +SELECT pg_sleep(0.1); -- assume a minimum timestamp granularity of 100ms + pg_sleep +---------- + +(1 row) + +-- cause one parallel sequential scan +BEGIN; +SET LOCAL parallel_setup_cost TO 0; +SET LOCAL min_parallel_table_scan_size TO '100kB'; +SET LOCAL min_parallel_index_scan_size TO '100kB'; +SET LOCAL enable_seqscan TO on; +SET LOCAL enable_indexscan TO off; +SET LOCAL enable_bitmapscan TO off; +SET LOCAL enable_indexonlyscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; + QUERY PLAN +----------------------------------------------------- + Aggregate + -> Gather + Workers Planned: 2 + -> Parallel Seq Scan on test_parallel_scan + Filter: (noidx_col = 1) +(5 rows) + +SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; + count +------- + 1 +(1 row) + +SELECT pg_stat_force_next_flush(); + pg_stat_force_next_flush +-------------------------- + +(1 row) + +COMMIT; +-- check that just sequential scan stats were incremented +SELECT parallel_seq_scan, :'test_last_seq' < last_parallel_seq_scan AS seq_ok, + parallel_idx_scan, :'test_last_idx' = last_parallel_idx_scan AS idx_ok +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + parallel_seq_scan | seq_ok | parallel_idx_scan | idx_ok +-------------------+--------+-------------------+-------- + 6 | t | 2 | t +(1 row) + +-- fetch timestamps from before the next test +SELECT last_parallel_seq_scan AS test_last_seq, last_parallel_idx_scan AS test_last_idx +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass \gset +SELECT pg_sleep(0.1); + pg_sleep +---------- + +(1 row) + +-- cause one parallel index scan +BEGIN; +SET LOCAL parallel_setup_cost TO 0; +SET LOCAL min_parallel_table_scan_size TO '100kB'; +SET LOCAL min_parallel_index_scan_size TO '100kB'; +SET LOCAL enable_seqscan TO off; +SET LOCAL enable_indexscan TO on; +SET LOCAL enable_bitmapscan TO off; +SET LOCAL enable_indexonlyscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; + QUERY PLAN +------------------------------------------------------------------------------------------- + Finalize Aggregate + -> Gather + Workers Planned: 1 + -> Partial Aggregate + -> Parallel Index Scan using test_parallel_scan_pkey on test_parallel_scan + Index Cond: ((idx_col >= 1) AND (idx_col <= 6000)) +(6 rows) + +SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; + count +------- + 6000 +(1 row) + +SELECT pg_stat_force_next_flush(); + pg_stat_force_next_flush +-------------------------- + +(1 row) + +COMMIT; +-- check that just index scan stats were incremented +SELECT parallel_seq_scan, :'test_last_seq' = last_parallel_seq_scan AS seq_ok, + parallel_idx_scan, :'test_last_idx' < last_parallel_idx_scan AS idx_ok +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + parallel_seq_scan | seq_ok | parallel_idx_scan | idx_ok +-------------------+--------+-------------------+-------- + 6 | t | 4 | t +(1 row) + +-- fetch timestamps from before the next test +SELECT last_parallel_seq_scan AS test_last_seq, last_parallel_idx_scan AS test_last_idx +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass \gset +SELECT pg_sleep(0.1); + pg_sleep +---------- + +(1 row) + ----- -- Test reset of some stats for shared table ----- diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index 7147cc2f89..5eb92fbf55 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -376,6 +376,98 @@ COMMIT; SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +----- +-- Test that parallel_seq_scan, last_parallel_seq_scan, parallel_idx_scan, last_parallel_idx_scan are correctly maintained +-- +-- We can't use a temporary table for parallel test. So, perform test using a permanent table, +-- but disable autovacuum on it. That way autovacuum etc won't +-- interfere. To be able to check that timestamps increase, we sleep for 100ms +-- between tests, assuming that there aren't systems with a coarser timestamp +-- granularity. +----- + +BEGIN; +CREATE TABLE test_parallel_scan(idx_col int primary key, noidx_col int) WITH (autovacuum_enabled = false); +INSERT INTO test_parallel_scan(idx_col, noidx_col) SELECT i, i FROM generate_series(1, 10_000) i; +COMMIT; + +VACUUM ANALYZE test_parallel_scan; + +SELECT pg_stat_force_next_flush(); + +SELECT parallel_seq_scan, last_parallel_seq_scan, parallel_idx_scan, last_parallel_idx_scan +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + +-- ensure we start out with exactly one parallel index and parallel sequential scan +BEGIN; +SET LOCAL parallel_setup_cost TO 0; +SET LOCAL min_parallel_table_scan_size TO '100kB'; +SET LOCAL min_parallel_index_scan_size TO '100kB'; +SET LOCAL enable_seqscan TO on; +SET LOCAL enable_indexscan TO on; +SET LOCAL enable_bitmapscan TO off; +SET LOCAL enable_indexonlyscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; +SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; +SET LOCAL enable_seqscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; +SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; +SELECT pg_stat_force_next_flush(); +COMMIT; + +-- fetch timestamps from before the next test +SELECT parallel_seq_scan, parallel_idx_scan +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; +SELECT last_parallel_seq_scan AS test_last_seq, last_parallel_idx_scan AS test_last_idx +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass \gset +SELECT pg_sleep(0.1); -- assume a minimum timestamp granularity of 100ms + +-- cause one parallel sequential scan +BEGIN; +SET LOCAL parallel_setup_cost TO 0; +SET LOCAL min_parallel_table_scan_size TO '100kB'; +SET LOCAL min_parallel_index_scan_size TO '100kB'; +SET LOCAL enable_seqscan TO on; +SET LOCAL enable_indexscan TO off; +SET LOCAL enable_bitmapscan TO off; +SET LOCAL enable_indexonlyscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; +SELECT count(*) FROM test_parallel_scan WHERE noidx_col = 1; +SELECT pg_stat_force_next_flush(); +COMMIT; +-- check that just sequential scan stats were incremented +SELECT parallel_seq_scan, :'test_last_seq' < last_parallel_seq_scan AS seq_ok, + parallel_idx_scan, :'test_last_idx' = last_parallel_idx_scan AS idx_ok +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + +-- fetch timestamps from before the next test +SELECT last_parallel_seq_scan AS test_last_seq, last_parallel_idx_scan AS test_last_idx +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass \gset +SELECT pg_sleep(0.1); + +-- cause one parallel index scan +BEGIN; +SET LOCAL parallel_setup_cost TO 0; +SET LOCAL min_parallel_table_scan_size TO '100kB'; +SET LOCAL min_parallel_index_scan_size TO '100kB'; +SET LOCAL enable_seqscan TO off; +SET LOCAL enable_indexscan TO on; +SET LOCAL enable_bitmapscan TO off; +SET LOCAL enable_indexonlyscan TO off; +EXPLAIN (COSTS off) SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; +SELECT count(*) FROM test_parallel_scan WHERE idx_col BETWEEN 1 AND 6000; +SELECT pg_stat_force_next_flush(); +COMMIT; +-- check that just index scan stats were incremented +SELECT parallel_seq_scan, :'test_last_seq' = last_parallel_seq_scan AS seq_ok, + parallel_idx_scan, :'test_last_idx' < last_parallel_idx_scan AS idx_ok +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass; + +-- fetch timestamps from before the next test +SELECT last_parallel_seq_scan AS test_last_seq, last_parallel_idx_scan AS test_last_idx +FROM pg_stat_all_tables WHERE relid = 'test_parallel_scan'::regclass \gset +SELECT pg_sleep(0.1); + ----- -- Test reset of some stats for shared table ----- -- 2.46.2