diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index fe80b8b0ba..a1defc6838 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -582,7 +582,7 @@ index_fetch_heap(IndexScanDesc scan, TupleTableSlot *slot) &scan->xs_heap_continue, &all_dead); if (found) - pgstat_count_heap_fetch(scan->indexRelation); + pgstat_count_index_fetch(scan->indexRelation); /* * If we scanned a whole HOT chain and found only dead tuples, tell index diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 5b49cc5a09..8a715db82e 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1853,7 +1853,7 @@ heap_drop_with_catalog(Oid relid) RelationDropStorage(rel); /* ensure that stats are dropped if transaction commits */ - pgstat_drop_relation(rel); + pgstat_drop_heap(rel); /* * Close relcache entry, but *keep* AccessExclusiveLock on the relation diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 61f1d3926a..28b94fef7f 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1752,7 +1752,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId); /* copy over statistics from old to new index */ - pgstat_copy_relation_stats(newClassRel, oldClassRel); + pgstat_copy_index_stats(newClassRel, oldClassRel); /* Copy data of pg_statistic from the old index to the new one */ CopyStatistics(oldIndexId, newIndexId); @@ -2326,7 +2326,7 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode) RelationDropStorage(userIndexRelation); /* ensure that stats are dropped if transaction commits */ - pgstat_drop_relation(userIndexRelation); + pgstat_drop_index(userIndexRelation); /* * Close and flush the index's relcache entry, to ensure relcache doesn't diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 2d8104b090..e92e50edf7 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -655,13 +655,13 @@ CREATE VIEW pg_stat_all_tables AS C.oid AS relid, N.nspname AS schemaname, 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_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_tuples_fetched(I.indexrelid))::bigint + - pg_stat_get_tuples_fetched(C.oid) AS idx_tup_fetch, + pg_stat_get_heap_numscans(C.oid) AS seq_scan, + pg_stat_get_heap_lastscan(C.oid) AS last_seq_scan, + pg_stat_get_heap_tuples_returned(C.oid) AS seq_tup_read, + sum(pg_stat_get_index_numscans(I.indexrelid))::bigint AS idx_scan, + max(pg_stat_get_index_lastscan(I.indexrelid)) AS last_idx_scan, + sum(pg_stat_get_index_tuples_fetched(I.indexrelid))::bigint + + pg_stat_get_heap_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, pg_stat_get_tuples_deleted(C.oid) AS n_tup_del, @@ -689,9 +689,9 @@ CREATE VIEW pg_stat_xact_all_tables AS C.oid AS relid, N.nspname AS schemaname, C.relname AS relname, - pg_stat_get_xact_numscans(C.oid) AS seq_scan, + pg_stat_get_heap_xact_numscans(C.oid) AS seq_scan, pg_stat_get_xact_tuples_returned(C.oid) AS seq_tup_read, - sum(pg_stat_get_xact_numscans(I.indexrelid))::bigint AS idx_scan, + sum(pg_stat_get_index_xact_numscans(I.indexrelid))::bigint AS idx_scan, sum(pg_stat_get_xact_tuples_fetched(I.indexrelid))::bigint + pg_stat_get_xact_tuples_fetched(C.oid) AS idx_tup_fetch, pg_stat_get_xact_tuples_inserted(C.oid) AS n_tup_ins, @@ -729,31 +729,31 @@ CREATE VIEW pg_statio_all_tables AS C.oid AS relid, N.nspname AS schemaname, C.relname AS relname, - pg_stat_get_blocks_fetched(C.oid) - - pg_stat_get_blocks_hit(C.oid) AS heap_blks_read, - pg_stat_get_blocks_hit(C.oid) AS heap_blks_hit, + pg_stat_get_heap_blocks_fetched(C.oid) - + pg_stat_get_heap_blocks_hit(C.oid) AS heap_blks_read, + pg_stat_get_heap_blocks_hit(C.oid) AS heap_blks_hit, I.idx_blks_read AS idx_blks_read, I.idx_blks_hit AS idx_blks_hit, - pg_stat_get_blocks_fetched(T.oid) - - pg_stat_get_blocks_hit(T.oid) AS toast_blks_read, - pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit, + pg_stat_get_heap_blocks_fetched(T.oid) - + pg_stat_get_heap_blocks_hit(T.oid) AS toast_blks_read, + pg_stat_get_heap_blocks_hit(T.oid) AS toast_blks_hit, X.idx_blks_read AS tidx_blks_read, X.idx_blks_hit AS tidx_blks_hit FROM pg_class C LEFT JOIN pg_class T ON C.reltoastrelid = T.oid LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) LEFT JOIN LATERAL ( - SELECT sum(pg_stat_get_blocks_fetched(indexrelid) - - pg_stat_get_blocks_hit(indexrelid))::bigint + SELECT sum(pg_stat_get_index_blocks_fetched(indexrelid) - + pg_stat_get_index_blocks_hit(indexrelid))::bigint AS idx_blks_read, - sum(pg_stat_get_blocks_hit(indexrelid))::bigint + sum(pg_stat_get_index_blocks_hit(indexrelid))::bigint AS idx_blks_hit FROM pg_index WHERE indrelid = C.oid ) I ON true LEFT JOIN LATERAL ( - SELECT sum(pg_stat_get_blocks_fetched(indexrelid) - - pg_stat_get_blocks_hit(indexrelid))::bigint + SELECT sum(pg_stat_get_index_blocks_fetched(indexrelid) - + pg_stat_get_index_blocks_hit(indexrelid))::bigint AS idx_blks_read, - sum(pg_stat_get_blocks_hit(indexrelid))::bigint + sum(pg_stat_get_index_blocks_hit(indexrelid))::bigint AS idx_blks_hit FROM pg_index WHERE indrelid = T.oid ) X ON true WHERE C.relkind IN ('r', 't', 'm'); @@ -775,10 +775,10 @@ CREATE VIEW pg_stat_all_indexes AS N.nspname AS schemaname, C.relname AS relname, 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_tuples_returned(I.oid) AS idx_tup_read, - pg_stat_get_tuples_fetched(I.oid) AS idx_tup_fetch + pg_stat_get_index_numscans(I.oid) AS idx_scan, + pg_stat_get_index_lastscan(I.oid) AS last_idx_scan, + pg_stat_get_index_tuples_returned(I.oid) AS idx_tup_read, + pg_stat_get_index_tuples_fetched(I.oid) AS idx_tup_fetch FROM pg_class C JOIN pg_index X ON C.oid = X.indrelid JOIN pg_class I ON I.oid = X.indexrelid @@ -802,9 +802,9 @@ CREATE VIEW pg_statio_all_indexes AS N.nspname AS schemaname, C.relname AS relname, I.relname AS indexrelname, - pg_stat_get_blocks_fetched(I.oid) - - pg_stat_get_blocks_hit(I.oid) AS idx_blks_read, - pg_stat_get_blocks_hit(I.oid) AS idx_blks_hit + pg_stat_get_index_blocks_fetched(I.oid) - + pg_stat_get_index_blocks_hit(I.oid) AS idx_blks_read, + pg_stat_get_index_blocks_hit(I.oid) AS idx_blks_hit FROM pg_class C JOIN pg_index X ON C.oid = X.indrelid JOIN pg_class I ON I.oid = X.indexrelid @@ -826,9 +826,9 @@ CREATE VIEW pg_statio_all_sequences AS C.oid AS relid, N.nspname AS schemaname, C.relname AS relname, - pg_stat_get_blocks_fetched(C.oid) - - pg_stat_get_blocks_hit(C.oid) AS blks_read, - pg_stat_get_blocks_hit(C.oid) AS blks_hit + pg_stat_get_index_blocks_fetched(C.oid) - + pg_stat_get_heap_blocks_hit(C.oid) AS blks_read, + pg_stat_get_heap_blocks_hit(C.oid) AS blks_hit FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE C.relkind = 'S'; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 73d30bf619..2e3b982aae 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -776,11 +776,19 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, * Read the buffer, and update pgstat counters to reflect a cache hit or * miss. */ - pgstat_count_buffer_read(reln); + if (reln->rd_rel->relkind == RELKIND_INDEX) + pgstat_count_index_buffer_read(reln); + else + pgstat_count_heap_buffer_read(reln); buf = ReadBuffer_common(RelationGetSmgr(reln), reln->rd_rel->relpersistence, forkNum, blockNum, mode, strategy, &hit); if (hit) - pgstat_count_buffer_hit(reln); + { + if (reln->rd_rel->relkind == RELKIND_INDEX) + pgstat_count_index_buffer_hit(reln); + else + pgstat_count_heap_buffer_hit(reln); + } return buf; } diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c index 1ebe3bbf29..9349d7f00c 100644 --- a/src/backend/utils/activity/pgstat.c +++ b/src/backend/utils/activity/pgstat.c @@ -269,18 +269,32 @@ static const PgStat_KindInfo pgstat_kind_infos[PGSTAT_NUM_KINDS] = { .reset_timestamp_cb = pgstat_database_reset_timestamp_cb, }, - [PGSTAT_KIND_RELATION] = { - .name = "relation", + [PGSTAT_KIND_TABLE] = { + .name = "table", .fixed_amount = false, - .shared_size = sizeof(PgStatShared_Relation), - .shared_data_off = offsetof(PgStatShared_Relation, stats), - .shared_data_len = sizeof(((PgStatShared_Relation *) 0)->stats), + .shared_size = sizeof(PgStatShared_Table), + .shared_data_off = offsetof(PgStatShared_Table, stats), + .shared_data_len = sizeof(((PgStatShared_Table *) 0)->stats), .pending_size = sizeof(PgStat_TableStatus), - .flush_pending_cb = pgstat_relation_flush_cb, - .delete_pending_cb = pgstat_relation_delete_pending_cb, + .flush_pending_cb = pgstat_table_flush_cb, + .delete_pending_cb = pgstat_table_delete_pending_cb, + }, + + [PGSTAT_KIND_INDEX] = { + .name = "index", + + .fixed_amount = false, + + .shared_size = sizeof(PgStatShared_Index), + .shared_data_off = offsetof(PgStatShared_Index, stats), + .shared_data_len = sizeof(((PgStatShared_Index *) 0)->stats), + .pending_size = sizeof(PgStat_IndexStatus), + + .flush_pending_cb = pgstat_index_flush_cb, + .delete_pending_cb = pgstat_index_delete_pending_cb, }, [PGSTAT_KIND_FUNCTION] = { diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c index 55a355f583..5d30b4c242 100644 --- a/src/backend/utils/activity/pgstat_relation.c +++ b/src/backend/utils/activity/pgstat_relation.c @@ -43,35 +43,35 @@ typedef struct TwoPhasePgStatRecord } TwoPhasePgStatRecord; -static PgStat_TableStatus *pgstat_prep_relation_pending(Oid rel_id, bool isshared); -static void add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level); -static void ensure_tabstat_xact_level(PgStat_TableStatus *pgstat_info); +static PgStat_TableStatus *pgstat_prep_table_pending(Oid rel_id, bool isshared); +static PgStat_IndexStatus *pgstat_prep_index_pending(Oid rel_id, bool isshared); +static void add_tabstat_xact_level(PgStat_TableStatus *pgstattab_info, int nest_level); +static void ensure_tabstat_xact_level(PgStat_TableStatus *pgstattab_info); static void save_truncdrop_counters(PgStat_TableXactStatus *trans, bool is_drop); static void restore_truncdrop_counters(PgStat_TableXactStatus *trans); - /* - * Copy stats between relations. This is used for things like REINDEX + * Copy stats between indexes. This is used for things like REINDEX * CONCURRENTLY. */ void -pgstat_copy_relation_stats(Relation dst, Relation src) +pgstat_copy_index_stats(Relation dst, Relation src) { - PgStat_StatTabEntry *srcstats; - PgStatShared_Relation *dstshstats; + PgStat_StatIndEntry *srcstats; + PgStatShared_Index *dstshstats; PgStat_EntryRef *dst_ref; - srcstats = pgstat_fetch_stat_tabentry_ext(src->rd_rel->relisshared, + srcstats = pgstat_fetch_stat_indentry_ext(src->rd_rel->relisshared, RelationGetRelid(src)); if (!srcstats) return; - dst_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, + dst_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_INDEX, dst->rd_rel->relisshared ? InvalidOid : MyDatabaseId, RelationGetRelid(dst), false); - dstshstats = (PgStatShared_Relation *) dst_ref->shared_stats; + dstshstats = (PgStatShared_Index *) dst_ref->shared_stats; dstshstats->stats = *srcstats; pgstat_unlock_entry(dst_ref); @@ -81,8 +81,9 @@ pgstat_copy_relation_stats(Relation dst, Relation src) * Initialize a relcache entry to count access statistics. Called whenever a * relation is opened. * - * We assume that a relcache entry's pgstat_info field is zeroed by relcache.c - * when the relcache entry is made; thereafter it is long-lived data. + * We assume that a relcache entry's pgstattab_info and pgstatind_info fields + * are zeroed by relcache.c when the relcache entry is made; thereafter it is + * long-lived data. * * This does not create a reference to a stats entry in shared memory, nor * allocate memory for the pending stats. That happens in @@ -99,18 +100,20 @@ pgstat_init_relation(Relation rel) if (!RELKIND_HAS_STORAGE(relkind) && relkind != RELKIND_PARTITIONED_TABLE) { rel->pgstat_enabled = false; - rel->pgstat_info = NULL; + rel->pgstattab_info = NULL; + rel->pgstatind_info = NULL; return; } if (!pgstat_track_counts) { - if (rel->pgstat_info) + if (rel->pgstattab_info != NULL || rel->pgstatind_info != NULL) pgstat_unlink_relation(rel); /* We're not counting at all */ rel->pgstat_enabled = false; - rel->pgstat_info = NULL; + rel->pgstattab_info = NULL; + rel->pgstatind_info = NULL; return; } @@ -118,10 +121,10 @@ pgstat_init_relation(Relation rel) } /* - * Prepare for statistics for this relation to be collected. + * Prepare for statistics for this table to be collected. * * This ensures we have a reference to the stats entry before stats can be - * generated. That is important because a relation drop in another connection + * generated. That is important because a table drop in another connection * could otherwise lead to the stats entry being dropped, which then later * would get recreated when flushing stats. * @@ -129,20 +132,48 @@ pgstat_init_relation(Relation rel) * relcache entries to be opened without ever getting stats reported. */ void -pgstat_assoc_relation(Relation rel) +pgstat_assoc_table(Relation rel) { Assert(rel->pgstat_enabled); - Assert(rel->pgstat_info == NULL); + Assert(rel->pgstattab_info == NULL); /* Else find or make the PgStat_TableStatus entry, and update link */ - rel->pgstat_info = pgstat_prep_relation_pending(RelationGetRelid(rel), + rel->pgstattab_info = pgstat_prep_table_pending(RelationGetRelid(rel), + rel->rd_rel->relisshared); + + /* don't allow link a stats to multiple relcache entries */ + Assert(rel->pgstattab_info->relation == NULL); + + /* mark this relation as the owner */ + rel->pgstattab_info->relation = rel; +} + +/* + * Prepare for statistics for this index to be collected. + * + * This ensures we have a reference to the stats entry before stats can be + * generated. That is important because an index drop in another + * connection could otherwise lead to the stats entry being dropped, which then + * later would get recreated when flushing stats. + * + * This is separate from pgstat_init_relation() as it is not uncommon for + * relcache entries to be opened without ever getting stats reported. + */ +void +pgstat_assoc_index(Relation rel) +{ + Assert(rel->pgstat_enabled); + Assert(rel->pgstatind_info == NULL); + + /* Else find or make the PgStat_IndexStatus entry, and update link */ + rel->pgstatind_info = pgstat_prep_index_pending(RelationGetRelid(rel), rel->rd_rel->relisshared); /* don't allow link a stats to multiple relcache entries */ - Assert(rel->pgstat_info->relation == NULL); + Assert(rel->pgstatind_info->relation == NULL); /* mark this relation as the owner */ - rel->pgstat_info->relation = rel; + rel->pgstatind_info->relation = rel; } /* @@ -152,14 +183,25 @@ pgstat_assoc_relation(Relation rel) void pgstat_unlink_relation(Relation rel) { - /* remove the link to stats info if any */ - if (rel->pgstat_info == NULL) + + if (rel->pgstatind_info == NULL && rel->pgstattab_info == NULL) return; - /* link sanity check */ - Assert(rel->pgstat_info->relation == rel); - rel->pgstat_info->relation = NULL; - rel->pgstat_info = NULL; + /* link sanity check for the table stats */ + if (rel->pgstattab_info) + { + Assert(rel->pgstattab_info->relation == rel); + rel->pgstattab_info->relation = NULL; + rel->pgstattab_info = NULL; + } + + /* link sanity check for the index stats */ + if (rel->pgstatind_info) + { + Assert(rel->pgstatind_info->relation == rel); + rel->pgstatind_info->relation = NULL; + rel->pgstatind_info = NULL; + } } /* @@ -168,39 +210,55 @@ pgstat_unlink_relation(Relation rel) void pgstat_create_relation(Relation rel) { - pgstat_create_transactional(PGSTAT_KIND_RELATION, - rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId, - RelationGetRelid(rel)); + if (rel->rd_rel->relkind == RELKIND_INDEX) + pgstat_create_transactional(PGSTAT_KIND_INDEX, + rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId, + RelationGetRelid(rel)); + else + pgstat_create_transactional(PGSTAT_KIND_TABLE, + rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId, + RelationGetRelid(rel)); +} + +/* + * Ensure that index stats are dropped if transaction commits. + */ +void +pgstat_drop_index(Relation rel) +{ + pgstat_drop_transactional(PGSTAT_KIND_INDEX, + rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId, + RelationGetRelid(rel)); } /* - * Ensure that stats are dropped if transaction commits. + * Ensure that table stats are dropped if transaction commits. */ void -pgstat_drop_relation(Relation rel) +pgstat_drop_heap(Relation rel) { int nest_level = GetCurrentTransactionNestLevel(); - PgStat_TableStatus *pgstat_info; + PgStat_TableStatus *pgstattab_info; - pgstat_drop_transactional(PGSTAT_KIND_RELATION, + pgstat_drop_transactional(PGSTAT_KIND_TABLE, rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId, RelationGetRelid(rel)); - if (!pgstat_should_count_relation(rel)) + if (!pgstat_should_count_table(rel)) return; /* * Transactionally set counters to 0. That ensures that accesses to * pg_stat_xact_all_tables inside the transaction show 0. */ - pgstat_info = rel->pgstat_info; - if (pgstat_info->trans && - pgstat_info->trans->nest_level == nest_level) + pgstattab_info = rel->pgstattab_info; + if (pgstattab_info->trans && + pgstattab_info->trans->nest_level == nest_level) { - save_truncdrop_counters(pgstat_info->trans, true); - pgstat_info->trans->tuples_inserted = 0; - pgstat_info->trans->tuples_updated = 0; - pgstat_info->trans->tuples_deleted = 0; + save_truncdrop_counters(pgstattab_info->trans, true); + pgstattab_info->trans->tuples_inserted = 0; + pgstattab_info->trans->tuples_updated = 0; + pgstattab_info->trans->tuples_deleted = 0; } } @@ -212,7 +270,7 @@ pgstat_report_vacuum(Oid tableoid, bool shared, PgStat_Counter livetuples, PgStat_Counter deadtuples) { PgStat_EntryRef *entry_ref; - PgStatShared_Relation *shtabentry; + PgStatShared_Table *shtabentry; PgStat_StatTabEntry *tabentry; Oid dboid = (shared ? InvalidOid : MyDatabaseId); TimestampTz ts; @@ -224,10 +282,10 @@ pgstat_report_vacuum(Oid tableoid, bool shared, ts = GetCurrentTimestamp(); /* block acquiring lock for the same reason as pgstat_report_autovac() */ - entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, + entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_TABLE, dboid, tableoid, false); - shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats; + shtabentry = (PgStatShared_Table *) entry_ref->shared_stats; tabentry = &shtabentry->stats; tabentry->n_live_tuples = livetuples; @@ -271,7 +329,7 @@ pgstat_report_analyze(Relation rel, bool resetcounter) { PgStat_EntryRef *entry_ref; - PgStatShared_Relation *shtabentry; + PgStatShared_Table *shtabentry; PgStat_StatTabEntry *tabentry; Oid dboid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId); @@ -290,31 +348,31 @@ pgstat_report_analyze(Relation rel, * * Waste no time on partitioned tables, though. */ - if (pgstat_should_count_relation(rel) && + if (pgstat_should_count_table(rel) && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) { PgStat_TableXactStatus *trans; - for (trans = rel->pgstat_info->trans; trans; trans = trans->upper) + for (trans = rel->pgstattab_info->trans; trans; trans = trans->upper) { livetuples -= trans->tuples_inserted - trans->tuples_deleted; deadtuples -= trans->tuples_updated + trans->tuples_deleted; } /* count stuff inserted by already-aborted subxacts, too */ - deadtuples -= rel->pgstat_info->t_counts.t_delta_dead_tuples; + deadtuples -= rel->pgstattab_info->t_counts.t_delta_dead_tuples; /* Since ANALYZE's counts are estimates, we could have underflowed */ livetuples = Max(livetuples, 0); deadtuples = Max(deadtuples, 0); } /* block acquiring lock for the same reason as pgstat_report_autovac() */ - entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, dboid, + entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_TABLE, dboid, RelationGetRelid(rel), false); /* can't get dropped while accessed */ Assert(entry_ref != NULL && entry_ref->shared_stats != NULL); - shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats; + shtabentry = (PgStatShared_Table *) entry_ref->shared_stats; tabentry = &shtabentry->stats; tabentry->n_live_tuples = livetuples; @@ -348,12 +406,12 @@ pgstat_report_analyze(Relation rel, void pgstat_count_heap_insert(Relation rel, PgStat_Counter n) { - if (pgstat_should_count_relation(rel)) + if (pgstat_should_count_table(rel)) { - PgStat_TableStatus *pgstat_info = rel->pgstat_info; + PgStat_TableStatus *pgstattab_info = rel->pgstattab_info; - ensure_tabstat_xact_level(pgstat_info); - pgstat_info->trans->tuples_inserted += n; + ensure_tabstat_xact_level(pgstattab_info); + pgstattab_info->trans->tuples_inserted += n; } } @@ -363,16 +421,16 @@ pgstat_count_heap_insert(Relation rel, PgStat_Counter n) void pgstat_count_heap_update(Relation rel, bool hot) { - if (pgstat_should_count_relation(rel)) + if (pgstat_should_count_table(rel)) { - PgStat_TableStatus *pgstat_info = rel->pgstat_info; + PgStat_TableStatus *pgstattab_info = rel->pgstattab_info; - ensure_tabstat_xact_level(pgstat_info); - pgstat_info->trans->tuples_updated++; + ensure_tabstat_xact_level(pgstattab_info); + pgstattab_info->trans->tuples_updated++; /* t_tuples_hot_updated is nontransactional, so just advance it */ if (hot) - pgstat_info->t_counts.t_tuples_hot_updated++; + pgstattab_info->t_counts.t_tuples_hot_updated++; } } @@ -382,12 +440,12 @@ pgstat_count_heap_update(Relation rel, bool hot) void pgstat_count_heap_delete(Relation rel) { - if (pgstat_should_count_relation(rel)) + if (pgstat_should_count_table(rel)) { - PgStat_TableStatus *pgstat_info = rel->pgstat_info; + PgStat_TableStatus *pgstattab_info = rel->pgstattab_info; - ensure_tabstat_xact_level(pgstat_info); - pgstat_info->trans->tuples_deleted++; + ensure_tabstat_xact_level(pgstattab_info); + pgstattab_info->trans->tuples_deleted++; } } @@ -397,15 +455,15 @@ pgstat_count_heap_delete(Relation rel) void pgstat_count_truncate(Relation rel) { - if (pgstat_should_count_relation(rel)) + if (pgstat_should_count_table(rel)) { - PgStat_TableStatus *pgstat_info = rel->pgstat_info; + PgStat_TableStatus *pgstattab_info = rel->pgstattab_info; - ensure_tabstat_xact_level(pgstat_info); - save_truncdrop_counters(pgstat_info->trans, false); - pgstat_info->trans->tuples_inserted = 0; - pgstat_info->trans->tuples_updated = 0; - pgstat_info->trans->tuples_deleted = 0; + ensure_tabstat_xact_level(pgstattab_info); + save_truncdrop_counters(pgstattab_info->trans, false); + pgstattab_info->trans->tuples_inserted = 0; + pgstattab_info->trans->tuples_updated = 0; + pgstattab_info->trans->tuples_deleted = 0; } } @@ -420,11 +478,11 @@ pgstat_count_truncate(Relation rel) void pgstat_update_heap_dead_tuples(Relation rel, int delta) { - if (pgstat_should_count_relation(rel)) + if (pgstat_should_count_table(rel)) { - PgStat_TableStatus *pgstat_info = rel->pgstat_info; + PgStat_TableStatus *pgstattab_info = rel->pgstattab_info; - pgstat_info->t_counts.t_delta_dead_tuples -= delta; + pgstattab_info->t_counts.t_delta_dead_tuples -= delta; } } @@ -460,7 +518,42 @@ pgstat_fetch_stat_tabentry_ext(bool shared, Oid reloid) Oid dboid = (shared ? InvalidOid : MyDatabaseId); return (PgStat_StatTabEntry *) - pgstat_fetch_entry(PGSTAT_KIND_RELATION, dboid, reloid); + pgstat_fetch_entry(PGSTAT_KIND_TABLE, dboid, reloid); +} + +/* + * Support function for the SQL-callable pgstat* functions. Returns + * the collected statistics for one index or NULL. NULL doesn't mean + * that the index doesn't exist, just that there are no statistics, so the + * caller is better off to report ZERO instead. + */ +PgStat_StatIndEntry * +pgstat_fetch_stat_indentry(Oid relid) +{ + PgStat_StatIndEntry *indentry; + + indentry = pgstat_fetch_stat_indentry_ext(false, relid); + if (indentry != NULL) + return indentry; + + /* + * If we didn't find it, maybe it's a shared index. + */ + indentry = pgstat_fetch_stat_indentry_ext(true, relid); + return indentry; +} + +/* + * More efficient version of pgstat_fetch_stat_indentry(), allowing to specify + * whether the to-be-accessed index is shared or not. + */ +PgStat_StatIndEntry * +pgstat_fetch_stat_indentry_ext(bool shared, Oid reloid) +{ + Oid dboid = (shared ? InvalidOid : MyDatabaseId); + + return (PgStat_StatIndEntry *) + pgstat_fetch_entry(PGSTAT_KIND_INDEX, dboid, reloid); } /* @@ -476,9 +569,31 @@ find_tabstat_entry(Oid rel_id) { PgStat_EntryRef *entry_ref; - entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, MyDatabaseId, rel_id); + entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_TABLE, MyDatabaseId, rel_id); + if (!entry_ref) + entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_TABLE, InvalidOid, rel_id); + + if (entry_ref) + return entry_ref->pending; + return NULL; +} + +/* + * find any existing PgStat_IndexStatus entry for rel + * + * Find any existing PgStat_IndexStatus entry for rel_id in the current + * database. If not found, try finding from shared indexes. + * + * If no entry found, return NULL, don't create a new one + */ +PgStat_IndexStatus * +find_indstat_entry(Oid rel_id) +{ + PgStat_EntryRef *entry_ref; + + entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_INDEX, MyDatabaseId, rel_id); if (!entry_ref) - entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, InvalidOid, rel_id); + entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_INDEX, InvalidOid, rel_id); if (entry_ref) return entry_ref->pending; @@ -694,27 +809,27 @@ pgstat_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len) { TwoPhasePgStatRecord *rec = (TwoPhasePgStatRecord *) recdata; - PgStat_TableStatus *pgstat_info; + PgStat_TableStatus *pgstattab_info; /* Find or create a tabstat entry for the rel */ - pgstat_info = pgstat_prep_relation_pending(rec->t_id, rec->t_shared); + pgstattab_info = pgstat_prep_table_pending(rec->t_id, rec->t_shared); /* Same math as in AtEOXact_PgStat, commit case */ - pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted; - pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; - pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; - pgstat_info->t_counts.t_truncdropped = rec->t_truncdropped; + pgstattab_info->t_counts.t_tuples_inserted += rec->tuples_inserted; + pgstattab_info->t_counts.t_tuples_updated += rec->tuples_updated; + pgstattab_info->t_counts.t_tuples_deleted += rec->tuples_deleted; + pgstattab_info->t_counts.t_truncdropped = rec->t_truncdropped; if (rec->t_truncdropped) { /* forget live/dead stats seen by backend thus far */ - pgstat_info->t_counts.t_delta_live_tuples = 0; - pgstat_info->t_counts.t_delta_dead_tuples = 0; + pgstattab_info->t_counts.t_delta_live_tuples = 0; + pgstattab_info->t_counts.t_delta_dead_tuples = 0; } - pgstat_info->t_counts.t_delta_live_tuples += + pgstattab_info->t_counts.t_delta_live_tuples += rec->tuples_inserted - rec->tuples_deleted; - pgstat_info->t_counts.t_delta_dead_tuples += + pgstattab_info->t_counts.t_delta_dead_tuples += rec->tuples_updated + rec->tuples_deleted; - pgstat_info->t_counts.t_changed_tuples += + pgstattab_info->t_counts.t_changed_tuples += rec->tuples_inserted + rec->tuples_updated + rec->tuples_deleted; } @@ -730,10 +845,10 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info, void *recdata, uint32 len) { TwoPhasePgStatRecord *rec = (TwoPhasePgStatRecord *) recdata; - PgStat_TableStatus *pgstat_info; + PgStat_TableStatus *pgstattab_info; /* Find or create a tabstat entry for the rel */ - pgstat_info = pgstat_prep_relation_pending(rec->t_id, rec->t_shared); + pgstattab_info = pgstat_prep_table_pending(rec->t_id, rec->t_shared); /* Same math as in AtEOXact_PgStat, abort case */ if (rec->t_truncdropped) @@ -742,10 +857,10 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info, rec->tuples_updated = rec->updated_pre_truncdrop; rec->tuples_deleted = rec->deleted_pre_truncdrop; } - pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted; - pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; - pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; - pgstat_info->t_counts.t_delta_dead_tuples += + pgstattab_info->t_counts.t_tuples_inserted += rec->tuples_inserted; + pgstattab_info->t_counts.t_tuples_updated += rec->tuples_updated; + pgstattab_info->t_counts.t_tuples_deleted += rec->tuples_deleted; + pgstattab_info->t_counts.t_delta_dead_tuples += rec->tuples_inserted + rec->tuples_updated; } @@ -759,22 +874,21 @@ pgstat_twophase_postabort(TransactionId xid, uint16 info, * entry when successfully flushing. */ bool -pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) +pgstat_table_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) { static const PgStat_TableCounts all_zeroes; Oid dboid; PgStat_TableStatus *lstats; /* pending stats entry */ - PgStatShared_Relation *shtabstats; + PgStatShared_Table *shtabstats; PgStat_StatTabEntry *tabentry; /* table entry of shared stats */ PgStat_StatDBEntry *dbentry; /* pending database entry */ dboid = entry_ref->shared_entry->key.dboid; lstats = (PgStat_TableStatus *) entry_ref->pending; - shtabstats = (PgStatShared_Relation *) entry_ref->shared_stats; + shtabstats = (PgStatShared_Table *) entry_ref->shared_stats; /* - * Ignore entries that didn't accumulate any actual counts, such as - * indexes that were opened by the planner but not used. + * Ignore entries that didn't accumulate any actual counts. */ if (memcmp(&lstats->t_counts, &all_zeroes, sizeof(PgStat_TableCounts)) == 0) @@ -792,6 +906,7 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) if (lstats->t_counts.t_numscans) { TimestampTz t = GetCurrentTransactionStopTimestamp(); + if (t > tabentry->lastscan) tabentry->lastscan = t; } @@ -839,8 +954,74 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) return true; } +/* + * Flush out pending stats for the entry + * + * If nowait is true, this function returns false if lock could not + * immediately acquired, otherwise true is returned. + * + * Some of the stats are copied to the corresponding pending database stats + * entry when successfully flushing. + */ +bool +pgstat_index_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) +{ + static const PgStat_IndexCounts all_zeroes; + Oid dboid; + + PgStat_IndexStatus *lstats; /* pending stats entry */ + PgStatShared_Index *shrelcomstats; + PgStat_StatIndEntry *indentry; /* index entry of shared stats */ + PgStat_StatDBEntry *dbentry; /* pending database entry */ + + dboid = entry_ref->shared_entry->key.dboid; + lstats = (PgStat_IndexStatus *) entry_ref->pending; + shrelcomstats = (PgStatShared_Index *) entry_ref->shared_stats; + + /* + * Ignore entries that didn't accumulate any actual counts, such as + * indexes that were opened by the planner but not used. + */ + if (memcmp(&lstats->i_counts, &all_zeroes, + sizeof(PgStat_IndexCounts)) == 0) + { + return true; + } + + if (!pgstat_lock_entry(entry_ref, nowait)) + return false; + + /* add the values to the shared entry. */ + indentry = &shrelcomstats->stats; + + indentry->numscans += lstats->i_counts.i_numscans; + + if (lstats->i_counts.i_numscans) + { + TimestampTz t = GetCurrentTransactionStopTimestamp(); + + if (t > indentry->lastscan) + indentry->lastscan = t; + } + indentry->tuples_returned += lstats->i_counts.i_tuples_returned; + indentry->tuples_fetched += lstats->i_counts.i_tuples_fetched; + indentry->blocks_fetched += lstats->i_counts.i_blocks_fetched; + indentry->blocks_hit += lstats->i_counts.i_blocks_hit; + + pgstat_unlock_entry(entry_ref); + + /* The entry was successfully flushed, add the same to database stats */ + dbentry = pgstat_prep_database_pending(dboid); + dbentry->n_tuples_returned += lstats->i_counts.i_tuples_returned; + dbentry->n_tuples_fetched += lstats->i_counts.i_tuples_fetched; + dbentry->n_blocks_fetched += lstats->i_counts.i_blocks_fetched; + dbentry->n_blocks_hit += lstats->i_counts.i_blocks_hit; + + return true; +} + void -pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref) +pgstat_table_delete_pending_cb(PgStat_EntryRef *entry_ref) { PgStat_TableStatus *pending = (PgStat_TableStatus *) entry_ref->pending; @@ -848,17 +1029,26 @@ pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref) pgstat_unlink_relation(pending->relation); } +void +pgstat_index_delete_pending_cb(PgStat_EntryRef *entry_ref) +{ + PgStat_IndexStatus *pending = (PgStat_IndexStatus *) entry_ref->pending; + + if (pending->relation) + pgstat_unlink_relation(pending->relation); +} + /* * Find or create a PgStat_TableStatus entry for rel. New entry is created and * initialized if not exists. */ static PgStat_TableStatus * -pgstat_prep_relation_pending(Oid rel_id, bool isshared) +pgstat_prep_table_pending(Oid rel_id, bool isshared) { PgStat_EntryRef *entry_ref; PgStat_TableStatus *pending; - entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_RELATION, + entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_TABLE, isshared ? InvalidOid : MyDatabaseId, rel_id, NULL); pending = entry_ref->pending; @@ -868,11 +1058,31 @@ pgstat_prep_relation_pending(Oid rel_id, bool isshared) return pending; } +/* + * Find or create a PgStat_IndexStatus entry for rel. New entry is created and + * initialized if not exists. + */ +static PgStat_IndexStatus * +pgstat_prep_index_pending(Oid rel_id, bool isshared) +{ + PgStat_EntryRef *entry_ref; + PgStat_IndexStatus *pending; + + entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_INDEX, + isshared ? InvalidOid : MyDatabaseId, + rel_id, NULL); + pending = entry_ref->pending; + pending->r_id = rel_id; + pending->r_shared = isshared; + + return pending; +} + /* * add a new (sub)transaction state record */ static void -add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level) +add_tabstat_xact_level(PgStat_TableStatus *pgstattab_info, int nest_level) { PgStat_SubXactStatus *xact_state; PgStat_TableXactStatus *trans; @@ -888,24 +1098,24 @@ add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level) MemoryContextAllocZero(TopTransactionContext, sizeof(PgStat_TableXactStatus)); trans->nest_level = nest_level; - trans->upper = pgstat_info->trans; - trans->parent = pgstat_info; + trans->upper = pgstattab_info->trans; + trans->parent = pgstattab_info; trans->next = xact_state->first; xact_state->first = trans; - pgstat_info->trans = trans; + pgstattab_info->trans = trans; } /* * Add a new (sub)transaction record if needed. */ static void -ensure_tabstat_xact_level(PgStat_TableStatus *pgstat_info) +ensure_tabstat_xact_level(PgStat_TableStatus *pgstattab_info) { int nest_level = GetCurrentTransactionNestLevel(); - if (pgstat_info->trans == NULL || - pgstat_info->trans->nest_level != nest_level) - add_tabstat_xact_level(pgstat_info, nest_level); + if (pgstattab_info->trans == NULL || + pgstattab_info->trans->nest_level != nest_level) + add_tabstat_xact_level(pgstattab_info, nest_level); } /* diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 96bffc0f2a..e1a5347e13 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -37,23 +37,37 @@ #define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role)) Datum -pg_stat_get_numscans(PG_FUNCTION_ARGS) +pg_stat_get_index_numscans(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; - PgStat_StatTabEntry *tabentry; + PgStat_StatIndEntry *indentry; - if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + if ((indentry = pgstat_fetch_stat_indentry(relid)) == NULL) result = 0; else - result = (int64) (tabentry->numscans); + result = (int64) (indentry->numscans); PG_RETURN_INT64(result); } +Datum +pg_stat_get_heap_numscans(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *relentry; + + if ((relentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (relentry->numscans); + + PG_RETURN_INT64(result); +} Datum -pg_stat_get_lastscan(PG_FUNCTION_ARGS) +pg_stat_get_heap_lastscan(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); PgStat_StatTabEntry *tabentry; @@ -61,12 +75,23 @@ pg_stat_get_lastscan(PG_FUNCTION_ARGS) if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) PG_RETURN_NULL(); else - PG_RETURN_TIMESTAMPTZ(tabentry->lastscan); + PG_RETURN_TIMESTAMPTZ(tabentry->lastscan);; } +Datum +pg_stat_get_index_lastscan(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + PgStat_StatIndEntry *indentry; + + if ((indentry = pgstat_fetch_stat_indentry(relid)) == NULL) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(indentry->lastscan);; +} Datum -pg_stat_get_tuples_returned(PG_FUNCTION_ARGS) +pg_stat_get_heap_tuples_returned(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; @@ -79,10 +104,23 @@ pg_stat_get_tuples_returned(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } +Datum +pg_stat_get_index_tuples_returned(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatIndEntry *indentry; + + if ((indentry = pgstat_fetch_stat_indentry(relid)) == NULL) + result = 0; + else + result = (int64) (indentry->tuples_returned); + PG_RETURN_INT64(result); +} Datum -pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS) +pg_stat_get_heap_tuples_fetched(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; @@ -96,6 +134,21 @@ pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } +Datum +pg_stat_get_index_tuples_fetched(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatIndEntry *indentry; + + if ((indentry = pgstat_fetch_stat_indentry(relid)) == NULL) + result = 0; + else + result = (int64) (indentry->tuples_fetched); + + PG_RETURN_INT64(result); +} + Datum pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS) @@ -226,7 +279,7 @@ pg_stat_get_ins_since_vacuum(PG_FUNCTION_ARGS) Datum -pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS) +pg_stat_get_heap_blocks_fetched(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; @@ -240,9 +293,23 @@ pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } +Datum +pg_stat_get_index_blocks_fetched(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatIndEntry *indentry; + + if ((indentry = pgstat_fetch_stat_indentry(relid)) == NULL) + result = 0; + else + result = (int64) (indentry->blocks_fetched); + + PG_RETURN_INT64(result); +} Datum -pg_stat_get_blocks_hit(PG_FUNCTION_ARGS) +pg_stat_get_heap_blocks_hit(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; @@ -256,6 +323,21 @@ pg_stat_get_blocks_hit(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } +Datum +pg_stat_get_index_blocks_hit(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatIndEntry *indentry; + + if ((indentry = pgstat_fetch_stat_indentry(relid)) == NULL) + result = 0; + else + result = (int64) (indentry->blocks_hit); + + PG_RETURN_INT64(result); +} + Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS) { @@ -1837,7 +1919,7 @@ pg_stat_get_slru(PG_FUNCTION_ARGS) } Datum -pg_stat_get_xact_numscans(PG_FUNCTION_ARGS) +pg_stat_get_heap_xact_numscans(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; @@ -1851,17 +1933,32 @@ pg_stat_get_xact_numscans(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } +Datum +pg_stat_get_index_xact_numscans(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_IndexStatus *indentry; + + if ((indentry = find_indstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (indentry->i_counts.i_numscans); + + PG_RETURN_INT64(result); +} + Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; - PgStat_TableStatus *tabentry; + PgStat_IndexStatus *indentry; - if ((tabentry = find_tabstat_entry(relid)) == NULL) + if ((indentry = find_indstat_entry(relid)) == NULL) result = 0; else - result = (int64) (tabentry->t_counts.t_tuples_returned); + result = (int64) (indentry->i_counts.i_tuples_returned); PG_RETURN_INT64(result); } @@ -1871,12 +1968,12 @@ pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; - PgStat_TableStatus *tabentry; + PgStat_IndexStatus *indentry; - if ((tabentry = find_tabstat_entry(relid)) == NULL) + if ((indentry = find_indstat_entry(relid)) == NULL) result = 0; else - result = (int64) (tabentry->t_counts.t_tuples_fetched); + result = (int64) (indentry->i_counts.i_tuples_fetched); PG_RETURN_INT64(result); } @@ -1964,12 +2061,12 @@ pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; - PgStat_TableStatus *tabentry; + PgStat_IndexStatus *indentry; - if ((tabentry = find_tabstat_entry(relid)) == NULL) + if ((indentry = find_indstat_entry(relid)) == NULL) result = 0; else - result = (int64) (tabentry->t_counts.t_blocks_fetched); + result = (int64) (indentry->i_counts.i_blocks_fetched); PG_RETURN_INT64(result); } @@ -1979,12 +2076,12 @@ pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); int64 result; - PgStat_TableStatus *tabentry; + PgStat_IndexStatus *indentry; - if ((tabentry = find_tabstat_entry(relid)) == NULL) + if ((indentry = find_indstat_entry(relid)) == NULL) result = 0; else - result = (int64) (tabentry->t_counts.t_blocks_hit); + result = (int64) (indentry->i_counts.i_blocks_hit); PG_RETURN_INT64(result); } @@ -2103,7 +2200,8 @@ pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS) { Oid taboid = PG_GETARG_OID(0); - pgstat_reset(PGSTAT_KIND_RELATION, MyDatabaseId, taboid); + pgstat_reset(PGSTAT_KIND_TABLE, MyDatabaseId, taboid); + pgstat_reset(PGSTAT_KIND_INDEX, MyDatabaseId, taboid); PG_RETURN_VOID(); } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index bd6cd4e47b..2d24abc3df 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2720,8 +2720,9 @@ RelationClearRelation(Relation relation, bool rebuild) SWAPFIELD(RowSecurityDesc *, rd_rsdesc); /* toast OID override must be preserved */ SWAPFIELD(Oid, rd_toastoid); - /* pgstat_info / enabled must be preserved */ - SWAPFIELD(struct PgStat_TableStatus *, pgstat_info); + /* pgstattab_info / pgstatind_info / enabled must be preserved */ + SWAPFIELD(struct PgStat_TableStatus *, pgstattab_info); + SWAPFIELD(struct PgStat_IndexStatus *, pgstatind_info); SWAPFIELD(bool, pgstat_enabled); /* preserve old partition key if we have one */ if (keep_partkey) @@ -6314,7 +6315,8 @@ load_relcache_init_file(bool shared) rel->rd_firstRelfilelocatorSubid = InvalidSubTransactionId; rel->rd_droppedSubid = InvalidSubTransactionId; rel->rd_amcache = NULL; - rel->pgstat_info = NULL; + rel->pgstattab_info = NULL; + rel->pgstatind_info = NULL; /* * Recompute lock and physical addressing info. This is needed in diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 20f5aa56ea..7733ebfcb9 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5248,22 +5248,38 @@ proargnames => '{mcv_list,index,values,nulls,frequency,base_frequency}', prosrc => 'pg_stats_ext_mcvlist_items' }, -{ oid => '1928', descr => 'statistics: number of scans done for table/index', - proname => 'pg_stat_get_numscans', provolatile => 's', proparallel => 'r', +{ oid => '1928', descr => 'statistics: number of scans done for table', + proname => 'pg_stat_get_heap_numscans', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', - prosrc => 'pg_stat_get_numscans' }, -{ oid => '9976', descr => 'statistics: time of the last scan for table/index', - proname => 'pg_stat_get_lastscan', provolatile => 's', proparallel => 'r', + prosrc => 'pg_stat_get_heap_numscans' }, +{ oid => '8296', descr => 'statistics: number of scans done for index', + proname => 'pg_stat_get_index_numscans', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_index_numscans' }, +{ oid => '9976', descr => 'statistics: time of the last scan for table', + proname => 'pg_stat_get_heap_lastscan', provolatile => 's', proparallel => 'r', + prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_heap_lastscan' }, +{ oid => '8626', descr => 'statistics: time of the last scan for index', + proname => 'pg_stat_get_index_lastscan', provolatile => 's', proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', - prosrc => 'pg_stat_get_lastscan' }, + prosrc => 'pg_stat_get_index_lastscan' }, { oid => '1929', descr => 'statistics: number of tuples read by seqscan', - proname => 'pg_stat_get_tuples_returned', provolatile => 's', + proname => 'pg_stat_get_heap_tuples_returned', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', - prosrc => 'pg_stat_get_tuples_returned' }, + prosrc => 'pg_stat_get_heap_tuples_returned' }, +{ oid => '9603', descr => 'statistics: number of tuples read by seqscan', + proname => 'pg_stat_get_index_tuples_returned', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_index_tuples_returned' }, { oid => '1930', descr => 'statistics: number of tuples fetched by idxscan', - proname => 'pg_stat_get_tuples_fetched', provolatile => 's', + proname => 'pg_stat_get_heap_tuples_fetched', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_heap_tuples_fetched' }, +{ oid => '8526', descr => 'statistics: number of tuples fetched by idxscan', + proname => 'pg_stat_get_index_tuples_fetched', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', - prosrc => 'pg_stat_get_tuples_fetched' }, + prosrc => 'pg_stat_get_index_tuples_fetched' }, { oid => '1931', descr => 'statistics: number of tuples inserted', proname => 'pg_stat_get_tuples_inserted', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', @@ -5299,13 +5315,21 @@ proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', prosrc => 'pg_stat_get_ins_since_vacuum' }, { oid => '1934', descr => 'statistics: number of blocks fetched', - proname => 'pg_stat_get_blocks_fetched', provolatile => 's', + proname => 'pg_stat_get_heap_blocks_fetched', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', - prosrc => 'pg_stat_get_blocks_fetched' }, + prosrc => 'pg_stat_get_heap_blocks_fetched' }, +{ oid => '9432', descr => 'statistics: number of blocks fetched', + proname => 'pg_stat_get_index_blocks_fetched', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_index_blocks_fetched' }, { oid => '1935', descr => 'statistics: number of blocks found in cache', - proname => 'pg_stat_get_blocks_hit', provolatile => 's', proparallel => 'r', + proname => 'pg_stat_get_heap_blocks_hit', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_heap_blocks_hit' }, +{ oid => '8354', descr => 'statistics: number of blocks found in cache', + proname => 'pg_stat_get_index_blocks_hit', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', - prosrc => 'pg_stat_get_blocks_hit' }, + prosrc => 'pg_stat_get_index_blocks_hit' }, { oid => '2781', descr => 'statistics: last manual vacuum time for a table', proname => 'pg_stat_get_last_vacuum_time', provolatile => 's', proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', @@ -5693,10 +5717,15 @@ prosrc => 'pg_stat_get_function_self_time' }, { oid => '3037', - descr => 'statistics: number of scans done for table/index in current transaction', - proname => 'pg_stat_get_xact_numscans', provolatile => 'v', + descr => 'statistics: number of scans done for table in current transaction', + proname => 'pg_stat_get_heap_xact_numscans', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_heap_xact_numscans' }, +{ oid => '8892', + descr => 'statistics: number of scans done for index in current transaction', + proname => 'pg_stat_get_index_xact_numscans', provolatile => 'v', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', - prosrc => 'pg_stat_get_xact_numscans' }, + prosrc => 'pg_stat_get_index_xact_numscans' }, { oid => '3038', descr => 'statistics: number of tuples read by seqscan in current transaction', proname => 'pg_stat_get_xact_tuples_returned', provolatile => 'v', diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 9e2ce6f011..65b1afe971 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -39,7 +39,8 @@ typedef enum PgStat_Kind /* stats for variable-numbered objects */ PGSTAT_KIND_DATABASE, /* database-wide statistics */ - PGSTAT_KIND_RELATION, /* per-table statistics */ + PGSTAT_KIND_TABLE, /* per-table statistics */ + PGSTAT_KIND_INDEX, /* per-index statistics */ PGSTAT_KIND_FUNCTION, /* per-function statistics */ PGSTAT_KIND_REPLSLOT, /* per-slot statistics */ PGSTAT_KIND_SUBSCRIPTION, /* per-subscription statistics */ @@ -145,6 +146,28 @@ typedef struct PgStat_BackendSubEntry PgStat_Counter sync_error_count; } PgStat_BackendSubEntry; +/* ---------- + * PgStat_IndexCounts The actual per-index counts kept by a backend + * + * This struct should contain only actual event counters, because we memcmp + * it against zeroes to detect whether there are any stats updates to apply. + * It is a component of PgStat_IndexStatus (within-backend state). + * + * tuples_returned is the number of index entries returned by + * the index AM, while tuples_fetched is the number of tuples successfully + * fetched by heap_fetch under the control of simple indexscans for this index. + * ---------- + */ +typedef struct PgStat_IndexCounts +{ + PgStat_Counter i_numscans; + + PgStat_Counter i_tuples_returned; + PgStat_Counter i_tuples_fetched; + PgStat_Counter i_blocks_fetched; + PgStat_Counter i_blocks_hit; +} PgStat_IndexCounts; + /* ---------- * PgStat_TableCounts The actual per-table counts kept by a backend * @@ -152,12 +175,9 @@ typedef struct PgStat_BackendSubEntry * it against zeroes to detect whether there are any stats updates to apply. * It is a component of PgStat_TableStatus (within-backend state). * - * Note: for a table, tuples_returned is the number of tuples successfully + * Note: tuples_returned is the number of tuples successfully * fetched by heap_getnext, while tuples_fetched is the number of tuples * successfully fetched by heap_fetch under the control of bitmap indexscans. - * For an index, tuples_returned is the number of index entries returned by - * the index AM, while tuples_fetched is the number of tuples successfully - * fetched by heap_fetch under the control of simple indexscans for this index. * * tuples_inserted/updated/deleted/hot_updated count attempted actions, * regardless of whether the transaction committed. delta_live_tuples, @@ -210,6 +230,22 @@ typedef struct PgStat_TableStatus Relation relation; /* rel that is using this entry */ } PgStat_TableStatus; +/* ---------- + * PgStat_IndexStatus Per-index status within a backend + * + * Many of the event counters are nontransactional, ie, we count events + * in committed and aborted transactions alike. For these, we just count + * directly in the PgStat_IndexStatus. + * ---------- + */ +typedef struct PgStat_IndexStatus +{ + Oid r_id; /* relation's OID */ + bool r_shared; /* is it a shared catalog? */ + PgStat_IndexCounts i_counts; /* event counts to be sent */ + Relation relation; /* rel that is using this entry */ +} PgStat_IndexStatus; + /* ---------- * PgStat_TableXactStatus Per-table, per-subtransaction status * ---------- @@ -382,6 +418,17 @@ typedef struct PgStat_StatTabEntry PgStat_Counter autovac_analyze_count; } PgStat_StatTabEntry; +typedef struct PgStat_StatIndEntry +{ + PgStat_Counter numscans; + TimestampTz lastscan; + + PgStat_Counter tuples_returned; + PgStat_Counter tuples_fetched; + PgStat_Counter blocks_fetched; + PgStat_Counter blocks_hit; +} PgStat_StatIndEntry; + typedef struct PgStat_WalStats { PgStat_Counter wal_records; @@ -498,11 +545,15 @@ extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id); */ extern void pgstat_create_relation(Relation rel); -extern void pgstat_drop_relation(Relation rel); -extern void pgstat_copy_relation_stats(Relation dst, Relation src); +extern void pgstat_create_table(Relation rel); +extern void pgstat_drop_heap(Relation rel); +extern void pgstat_drop_index(Relation rel); +extern void pgstat_copy_index_stats(Relation dst, Relation src); extern void pgstat_init_relation(Relation rel); extern void pgstat_assoc_relation(Relation rel); +extern void pgstat_assoc_table(Relation rel); +extern void pgstat_assoc_index(Relation rel); extern void pgstat_unlink_relation(Relation rel); extern void pgstat_report_vacuum(Oid tableoid, bool shared, @@ -513,51 +564,69 @@ extern void pgstat_report_analyze(Relation rel, /* * If stats are enabled, but pending data hasn't been prepared yet, call - * pgstat_assoc_relation() to do so. See its comment for why this is done - * separately from pgstat_init_relation(). + * pgstat_assoc_table() / pgstat_assoc_index() to do so. + * See their comment for why this is done separately from pgstat_init_relation(). */ -#define pgstat_should_count_relation(rel) \ - (likely((rel)->pgstat_info != NULL) ? true : \ - ((rel)->pgstat_enabled ? pgstat_assoc_relation(rel), true : false)) +#define pgstat_should_count_table(rel) \ + (likely((rel)->pgstattab_info != NULL) ? true : \ + ((rel)->pgstat_enabled ? pgstat_assoc_table(rel), true : false)) + +#define pgstat_should_count_index(rel) \ + (likely((rel)->pgstatind_info != NULL) ? true : \ + ((rel)->pgstat_enabled ? pgstat_assoc_index(rel), true : false)) /* nontransactional event counts are simple enough to inline */ #define pgstat_count_heap_scan(rel) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_numscans++; \ + if (pgstat_should_count_table(rel)) \ + (rel)->pgstattab_info->t_counts.t_numscans++; \ } while (0) #define pgstat_count_heap_getnext(rel) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_tuples_returned++; \ + if (pgstat_should_count_table(rel)) \ + (rel)->pgstattab_info->t_counts.t_tuples_returned++; \ } while (0) #define pgstat_count_heap_fetch(rel) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_tuples_fetched++; \ + if (pgstat_should_count_table(rel)) \ + (rel)->pgstattab_info->t_counts.t_tuples_fetched++; \ + } while (0) +#define pgstat_count_index_fetch(rel) \ + do { \ + if (pgstat_should_count_index(rel)) \ + (rel)->pgstatind_info->i_counts.i_tuples_fetched++; \ } while (0) #define pgstat_count_index_scan(rel) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_numscans++; \ + if (pgstat_should_count_index(rel)) \ + (rel)->pgstatind_info->i_counts.i_numscans++; \ } while (0) #define pgstat_count_index_tuples(rel, n) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_tuples_returned += (n); \ + if (pgstat_should_count_index(rel)) \ + (rel)->pgstatind_info->i_counts.i_tuples_returned += (n); \ } while (0) -#define pgstat_count_buffer_read(rel) \ +#define pgstat_count_heap_buffer_read(rel) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_blocks_fetched++; \ + if (pgstat_should_count_table(rel)) \ + (rel)->pgstattab_info->t_counts.t_blocks_fetched++; \ } while (0) -#define pgstat_count_buffer_hit(rel) \ +#define pgstat_count_index_buffer_read(rel) \ do { \ - if (pgstat_should_count_relation(rel)) \ - (rel)->pgstat_info->t_counts.t_blocks_hit++; \ + if (pgstat_should_count_index(rel)) \ + (rel)->pgstatind_info->i_counts.i_blocks_fetched++; \ + } while (0) +#define pgstat_count_heap_buffer_hit(rel) \ + do { \ + if (pgstat_should_count_table(rel)) \ + (rel)->pgstattab_info->t_counts.t_blocks_hit++; \ + } while (0) +#define pgstat_count_index_buffer_hit(rel) \ + do { \ + if (pgstat_should_count_index(rel)) \ + (rel)->pgstatind_info->i_counts.i_blocks_hit++; \ } while (0) - extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n); extern void pgstat_count_heap_update(Relation rel, bool hot); extern void pgstat_count_heap_delete(Relation rel); @@ -573,6 +642,10 @@ extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid); extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_ext(bool shared, Oid reloid); extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id); +extern PgStat_IndexStatus *find_indstat_entry(Oid rel_id); +extern PgStat_StatIndEntry *pgstat_fetch_stat_indentry(Oid relid); +extern PgStat_StatIndEntry *pgstat_fetch_stat_indentry_ext(bool shared, + Oid relid); /* diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h index c869533b28..b7464b5a5c 100644 --- a/src/include/utils/pgstat_internal.h +++ b/src/include/utils/pgstat_internal.h @@ -360,11 +360,17 @@ typedef struct PgStatShared_Database PgStat_StatDBEntry stats; } PgStatShared_Database; -typedef struct PgStatShared_Relation +typedef struct PgStatShared_Table { PgStatShared_Common header; PgStat_StatTabEntry stats; -} PgStatShared_Relation; +} PgStatShared_Table; + +typedef struct PgStatShared_Index +{ + PgStatShared_Common header; + PgStat_StatIndEntry stats; +} PgStatShared_Index; typedef struct PgStatShared_Function { @@ -559,8 +565,10 @@ extern void AtEOSubXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool extern void AtPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state); extern void PostPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state); -extern bool pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); -extern void pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref); +extern bool pgstat_table_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); +extern bool pgstat_index_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); +extern void pgstat_table_delete_pending_cb(PgStat_EntryRef *entry_ref); +extern void pgstat_index_delete_pending_cb(PgStat_EntryRef *entry_ref); /* diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index f383a2fca9..796423f3e3 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -248,7 +248,10 @@ typedef struct RelationData bool pgstat_enabled; /* should relation stats be counted */ /* use "struct" here to avoid needing to include pgstat.h: */ - struct PgStat_TableStatus *pgstat_info; /* statistics collection area */ + /* table's statistics collection area */ + struct PgStat_TableStatus *pgstattab_info; + /* Index's statistics collection area */ + struct PgStat_IndexStatus *pgstatind_info; } RelationData; diff --git a/src/test/isolation/expected/stats.out b/src/test/isolation/expected/stats.out index 61b5a710ec..6ff2cfbd97 100644 --- a/src/test/isolation/expected/stats.out +++ b/src/test/isolation/expected/stats.out @@ -2166,8 +2166,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2210,8 +2210,8 @@ step s2_table_update_k1: UPDATE test_stat_tab SET value = value + 1 WHERE key = step s1_table_drop: DROP TABLE test_stat_tab; step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2236,8 +2236,8 @@ pg_stat_force_next_flush step s1_track_counts_off: SET track_counts = off; step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2275,8 +2275,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2314,8 +2314,8 @@ pg_stat_force_next_flush step s1_track_counts_off: SET track_counts = off; step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2369,8 +2369,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2401,8 +2401,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2463,8 +2463,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2495,8 +2495,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2558,8 +2558,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2627,8 +2627,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2688,8 +2688,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2755,8 +2755,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2795,8 +2795,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2841,8 +2841,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2881,8 +2881,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2927,8 +2927,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -2968,8 +2968,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, @@ -3015,8 +3015,8 @@ pg_stat_force_next_flush step s1_table_stats: SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, diff --git a/src/test/isolation/specs/stats.spec b/src/test/isolation/specs/stats.spec index 5b922d788c..0ca25393e4 100644 --- a/src/test/isolation/specs/stats.spec +++ b/src/test/isolation/specs/stats.spec @@ -93,8 +93,8 @@ step s1_table_drop { DROP TABLE test_stat_tab; } step s1_table_stats { SELECT - pg_stat_get_numscans(tso.oid) AS seq_scan, - pg_stat_get_tuples_returned(tso.oid) AS seq_tup_read, + pg_stat_get_heap_numscans(tso.oid) AS seq_scan, + pg_stat_get_heap_tuples_returned(tso.oid) AS seq_tup_read, pg_stat_get_tuples_inserted(tso.oid) AS n_tup_ins, pg_stat_get_tuples_updated(tso.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(tso.oid) AS n_tup_del, diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl index 1bf7b568cc..c25634d33f 100644 --- a/src/test/recovery/t/029_stats_restart.pl +++ b/src/test/recovery/t/029_stats_restart.pl @@ -43,8 +43,8 @@ my $sect = "initial"; is(have_stats('database', $dboid, 0), 't', "$sect: db stats do exist"); is(have_stats('function', $dboid, $funcoid), 't', "$sect: function stats do exist"); -is(have_stats('relation', $dboid, $tableoid), - 't', "$sect: relation stats do exist"); +is(have_stats('table', $dboid, $tableoid), + 't', "$sect: table stats do exist"); # regular shutdown $node->stop(); @@ -67,8 +67,8 @@ $sect = "copy"; is(have_stats('database', $dboid, 0), 't', "$sect: db stats do exist"); is(have_stats('function', $dboid, $funcoid), 't', "$sect: function stats do exist"); -is(have_stats('relation', $dboid, $tableoid), - 't', "$sect: relation stats do exist"); +is(have_stats('table', $dboid, $tableoid), + 't', "$sect: table stats do exist"); $node->stop('immediate'); @@ -84,8 +84,8 @@ $sect = "post immediate"; is(have_stats('database', $dboid, 0), 'f', "$sect: db stats do not exist"); is(have_stats('function', $dboid, $funcoid), 'f', "$sect: function stats do exist"); -is(have_stats('relation', $dboid, $tableoid), - 'f', "$sect: relation stats do not exist"); +is(have_stats('table', $dboid, $tableoid), + 'f', "$sect: table stats do not exist"); # get rid of backup statsfile unlink $statsfile or die "cannot unlink $statsfile $!"; @@ -98,8 +98,8 @@ $sect = "post immediate, new"; is(have_stats('database', $dboid, 0), 't', "$sect: db stats do exist"); is(have_stats('function', $dboid, $funcoid), 't', "$sect: function stats do exist"); -is(have_stats('relation', $dboid, $tableoid), - 't', "$sect: relation stats do exist"); +is(have_stats('table', $dboid, $tableoid), + 't', "$sect: table stats do exist"); # regular shutdown $node->stop(); @@ -117,8 +117,7 @@ $sect = "invalid_overwrite"; is(have_stats('database', $dboid, 0), 'f', "$sect: db stats do not exist"); is(have_stats('function', $dboid, $funcoid), 'f', "$sect: function stats do not exist"); -is(have_stats('relation', $dboid, $tableoid), - 'f', "$sect: relation stats do not exist"); +is(have_stats('table', $dboid, $tableoid), 'f', "$sect: table do not exist"); ## check invalid stats file starting with valid contents, but followed by @@ -133,8 +132,8 @@ $sect = "invalid_append"; is(have_stats('database', $dboid, 0), 'f', "$sect: db stats do not exist"); is(have_stats('function', $dboid, $funcoid), 'f', "$sect: function stats do not exist"); -is(have_stats('relation', $dboid, $tableoid), - 'f', "$sect: relation stats do not exist"); +is(have_stats('table', $dboid, $tableoid), + 'f', "$sect: table stats do not exist"); ## checks related to stats persistency around restarts and resets diff --git a/src/test/recovery/t/030_stats_cleanup_replica.pl b/src/test/recovery/t/030_stats_cleanup_replica.pl index cc92ddbb52..1e78b13cf9 100644 --- a/src/test/recovery/t/030_stats_cleanup_replica.pl +++ b/src/test/recovery/t/030_stats_cleanup_replica.pl @@ -185,7 +185,7 @@ sub test_standby_func_tab_stats_status my %stats; $stats{rel} = $node_standby->safe_psql($connect_db, - "SELECT pg_stat_have_stats('relation', $dboid, $tableoid)"); + "SELECT pg_stat_have_stats('table', $dboid, $tableoid)"); $stats{func} = $node_standby->safe_psql($connect_db, "SELECT pg_stat_have_stats('function', $dboid, $funcoid)"); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 624d0e5aae..531164e030 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1764,10 +1764,10 @@ pg_stat_all_indexes| SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, 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_tuples_returned(i.oid) AS idx_tup_read, - pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch + pg_stat_get_index_numscans(i.oid) AS idx_scan, + pg_stat_get_index_lastscan(i.oid) AS last_idx_scan, + pg_stat_get_index_tuples_returned(i.oid) AS idx_tup_read, + pg_stat_get_index_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) @@ -1776,12 +1776,12 @@ pg_stat_all_indexes| SELECT c.oid AS relid, pg_stat_all_tables| SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, - pg_stat_get_numscans(c.oid) AS seq_scan, - pg_stat_get_lastscan(c.oid) AS last_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_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, + pg_stat_get_heap_numscans(c.oid) AS seq_scan, + pg_stat_get_heap_lastscan(c.oid) AS last_seq_scan, + pg_stat_get_heap_tuples_returned(c.oid) AS seq_tup_read, + (sum(pg_stat_get_index_numscans(i.indexrelid)))::bigint AS idx_scan, + max(pg_stat_get_index_lastscan(i.indexrelid)) AS last_idx_scan, + ((sum(pg_stat_get_index_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_heap_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, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, @@ -2221,9 +2221,9 @@ pg_stat_wal_receiver| SELECT s.pid, pg_stat_xact_all_tables| SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, - pg_stat_get_xact_numscans(c.oid) AS seq_scan, + pg_stat_get_heap_xact_numscans(c.oid) AS seq_scan, pg_stat_get_xact_tuples_returned(c.oid) AS seq_tup_read, - (sum(pg_stat_get_xact_numscans(i.indexrelid)))::bigint AS idx_scan, + (sum(pg_stat_get_index_xact_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_xact_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_xact_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_xact_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_xact_tuples_updated(c.oid) AS n_tup_upd, @@ -2274,8 +2274,8 @@ pg_statio_all_indexes| SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, - (pg_stat_get_blocks_fetched(i.oid) - pg_stat_get_blocks_hit(i.oid)) AS idx_blks_read, - pg_stat_get_blocks_hit(i.oid) AS idx_blks_hit + (pg_stat_get_index_blocks_fetched(i.oid) - pg_stat_get_index_blocks_hit(i.oid)) AS idx_blks_read, + pg_stat_get_index_blocks_hit(i.oid) AS idx_blks_hit FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) @@ -2284,31 +2284,31 @@ pg_statio_all_indexes| SELECT c.oid AS relid, pg_statio_all_sequences| SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, - (pg_stat_get_blocks_fetched(c.oid) - pg_stat_get_blocks_hit(c.oid)) AS blks_read, - pg_stat_get_blocks_hit(c.oid) AS blks_hit + (pg_stat_get_index_blocks_fetched(c.oid) - pg_stat_get_heap_blocks_hit(c.oid)) AS blks_read, + pg_stat_get_heap_blocks_hit(c.oid) AS blks_hit FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'S'::"char"); pg_statio_all_tables| SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, - (pg_stat_get_blocks_fetched(c.oid) - pg_stat_get_blocks_hit(c.oid)) AS heap_blks_read, - pg_stat_get_blocks_hit(c.oid) AS heap_blks_hit, + (pg_stat_get_heap_blocks_fetched(c.oid) - pg_stat_get_heap_blocks_hit(c.oid)) AS heap_blks_read, + pg_stat_get_heap_blocks_hit(c.oid) AS heap_blks_hit, i.idx_blks_read, i.idx_blks_hit, - (pg_stat_get_blocks_fetched(t.oid) - pg_stat_get_blocks_hit(t.oid)) AS toast_blks_read, - pg_stat_get_blocks_hit(t.oid) AS toast_blks_hit, + (pg_stat_get_heap_blocks_fetched(t.oid) - pg_stat_get_heap_blocks_hit(t.oid)) AS toast_blks_read, + pg_stat_get_heap_blocks_hit(t.oid) AS toast_blks_hit, x.idx_blks_read AS tidx_blks_read, x.idx_blks_hit AS tidx_blks_hit FROM ((((pg_class c LEFT JOIN pg_class t ON ((c.reltoastrelid = t.oid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) - LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_blocks_fetched(pg_index.indexrelid) - pg_stat_get_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read, - (sum(pg_stat_get_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit + LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_index_blocks_fetched(pg_index.indexrelid) - pg_stat_get_index_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read, + (sum(pg_stat_get_index_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit FROM pg_index WHERE (pg_index.indrelid = c.oid)) i ON (true)) - LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_blocks_fetched(pg_index.indexrelid) - pg_stat_get_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read, - (sum(pg_stat_get_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit + LEFT JOIN LATERAL ( SELECT (sum((pg_stat_get_index_blocks_fetched(pg_index.indexrelid) - pg_stat_get_index_blocks_hit(pg_index.indexrelid))))::bigint AS idx_blks_read, + (sum(pg_stat_get_index_blocks_hit(pg_index.indexrelid)))::bigint AS idx_blks_hit FROM pg_index WHERE (pg_index.indrelid = t.oid)) x ON (true)) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"])); diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index 257a6a9da9..449d70f4c7 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -151,6 +151,117 @@ FROM prevstats AS pr; COMMIT; ---- +-- Basic tests for toast +--- +CREATE TABLE stats_toast(stuff text); +ALTER TABLE stats_toast ALTER COLUMN stuff SET STORAGE EXTERNAL; +INSERT INTO stats_toast VALUES (repeat('a',1000000)); +SELECT count(*) FROM stats_toast WHERE stuff like '%a%'; + count +------- + 1 +(1 row) + +-- ensure pending stats are flushed +SELECT pg_stat_force_next_flush(); + pg_stat_force_next_flush +-------------------------- + +(1 row) + +select toast_blks_read > 0 as toast_blks_read, toast_blks_hit > 0 as toast_blks_hit, + tidx_blks_read > 0 as tidx_blks_read, tidx_blks_hit > 0 as tidx_blks_hit, + toast_blks_hit >= toast_blks_read, + tidx_blks_hit >= tidx_blks_read + from pg_statio_all_tables + where relname = 'stats_toast'; + toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit | ?column? | ?column? +-----------------+----------------+----------------+---------------+----------+---------- + t | t | t | t | t | t +(1 row) + +---- +-- Basic tests for partition +--- +CREATE TABLE stats_partition ( + id1 int not null, + id2 int not null +) PARTITION BY RANGE (id2); +CREATE TABLE stats_partition_5 PARTITION OF stats_partition + FOR VALUES FROM (0) TO (5); +CREATE TABLE stats_partition_20000 PARTITION OF stats_partition + FOR VALUES FROM (5) TO (20001); +CREATE INDEX ON stats_partition (id2); +insert into stats_partition select a,a from generate_series(0,20000) a; +SET enable_seqscan TO off; +SET enable_bitmapscan TO off; +select * from stats_partition where id2 = 2000; + id1 | id2 +------+------ + 2000 | 2000 +(1 row) + +select * from stats_partition where id2 = 2; + id1 | id2 +-----+----- + 2 | 2 +(1 row) + +-- ensure pending stats are flushed +SELECT pg_stat_force_next_flush(); + pg_stat_force_next_flush +-------------------------- + +(1 row) + +select relname, indexrelname, idx_scan > 0 as idx_scan, idx_tup_read > 0 as idx_tup_read, + idx_tup_fetch > 0 as idx_tup_fetch + from pg_stat_all_indexes + where relname like '%stats_partition%' + order by relname COLLATE "C"; + relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch +-----------------------+-------------------------------+----------+--------------+--------------- + stats_partition_20000 | stats_partition_20000_id2_idx | t | t | t + stats_partition_5 | stats_partition_5_id2_idx | t | t | t +(2 rows) + +select relname, indexrelname, idx_blks_read > 0 as idx_blks_read, + idx_blks_hit > 0 as idx_blks_hit + from pg_statio_all_indexes + where relname like '%stats_partition%' + order by relname COLLATE "C"; + relname | indexrelname | idx_blks_read | idx_blks_hit +-----------------------+-------------------------------+---------------+-------------- + stats_partition_20000 | stats_partition_20000_id2_idx | t | t + stats_partition_5 | stats_partition_5_id2_idx | t | t +(2 rows) + +select relname,seq_scan > 0 as seq_scan, seq_tup_read > 0 as seq_tup_read, + idx_scan > 0 as idx_scan, idx_tup_fetch > 0 as idx_tup_fetch + from pg_stat_all_tables + where relname like '%stats_partition%' + order by relname COLLATE "C"; + relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch +-----------------------+----------+--------------+----------+--------------- + stats_partition | f | f | f | f + stats_partition_20000 | t | f | t | t + stats_partition_5 | t | f | t | t +(3 rows) + +select relname, heap_blks_read > 0 as heap_blks_read, heap_blks_hit > 0 as heap_blks_hit, + idx_blks_read > 0 as idx_blks_read, idx_blks_hit > 0 as idx_blks_hit + from pg_statio_all_tables + where relname like '%stats_partition%' + order by relname COLLATE "C"; + relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit +-----------------------+----------------+---------------+---------------+-------------- + stats_partition_20000 | t | t | t | t + stats_partition_5 | t | t | t | t +(2 rows) + +SET enable_seqscan TO on; +SET enable_bitmapscan TO on; +---- -- Basic tests for track_functions --- CREATE FUNCTION stats_test_func1() RETURNS VOID LANGUAGE plpgsql AS $$BEGIN END;$$; @@ -1015,21 +1126,21 @@ select a from stats_test_tab1 where a = 3; 3 (1 row) -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t (1 row) -- pg_stat_have_stats returns false for dropped index with stats -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t (1 row) DROP index stats_test_idx1; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- f @@ -1045,14 +1156,14 @@ select a from stats_test_tab1 where a = 3; 3 (1 row) -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t (1 row) ROLLBACK; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- f @@ -1067,7 +1178,7 @@ select a from stats_test_tab1 where a = 3; 3 (1 row) -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t @@ -1075,7 +1186,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); REINDEX index CONCURRENTLY stats_test_idx1; -- false for previous oid -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- f @@ -1083,7 +1194,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); -- true for new oid SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t @@ -1091,7 +1202,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); -- pg_stat_have_stats returns true for a rolled back drop index with stats BEGIN; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t @@ -1099,7 +1210,7 @@ SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); DROP index stats_test_idx1; ROLLBACK; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); pg_stat_have_stats -------------------- t diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index f6270f7bad..c7fee71d6f 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -126,6 +126,77 @@ FROM prevstats AS pr; COMMIT; +---- +-- Basic tests for toast +--- +CREATE TABLE stats_toast(stuff text); +ALTER TABLE stats_toast ALTER COLUMN stuff SET STORAGE EXTERNAL; +INSERT INTO stats_toast VALUES (repeat('a',1000000)); +SELECT count(*) FROM stats_toast WHERE stuff like '%a%'; + +-- ensure pending stats are flushed +SELECT pg_stat_force_next_flush(); + +select toast_blks_read > 0 as toast_blks_read, toast_blks_hit > 0 as toast_blks_hit, + tidx_blks_read > 0 as tidx_blks_read, tidx_blks_hit > 0 as tidx_blks_hit, + toast_blks_hit >= toast_blks_read, + tidx_blks_hit >= tidx_blks_read + from pg_statio_all_tables + where relname = 'stats_toast'; + +---- +-- Basic tests for partition +--- +CREATE TABLE stats_partition ( + id1 int not null, + id2 int not null +) PARTITION BY RANGE (id2); + +CREATE TABLE stats_partition_5 PARTITION OF stats_partition + FOR VALUES FROM (0) TO (5); + +CREATE TABLE stats_partition_20000 PARTITION OF stats_partition + FOR VALUES FROM (5) TO (20001); + +CREATE INDEX ON stats_partition (id2); + +insert into stats_partition select a,a from generate_series(0,20000) a; + +SET enable_seqscan TO off; +SET enable_bitmapscan TO off; + +select * from stats_partition where id2 = 2000; +select * from stats_partition where id2 = 2; +-- ensure pending stats are flushed +SELECT pg_stat_force_next_flush(); + +select relname, indexrelname, idx_scan > 0 as idx_scan, idx_tup_read > 0 as idx_tup_read, + idx_tup_fetch > 0 as idx_tup_fetch + from pg_stat_all_indexes + where relname like '%stats_partition%' + order by relname COLLATE "C"; + +select relname, indexrelname, idx_blks_read > 0 as idx_blks_read, + idx_blks_hit > 0 as idx_blks_hit + from pg_statio_all_indexes + where relname like '%stats_partition%' + order by relname COLLATE "C"; + +select relname,seq_scan > 0 as seq_scan, seq_tup_read > 0 as seq_tup_read, + idx_scan > 0 as idx_scan, idx_tup_fetch > 0 as idx_tup_fetch + from pg_stat_all_tables + where relname like '%stats_partition%' + order by relname COLLATE "C"; + +select relname, heap_blks_read > 0 as heap_blks_read, heap_blks_hit > 0 as heap_blks_hit, + idx_blks_read > 0 as idx_blks_read, idx_blks_hit > 0 as idx_blks_hit + from pg_statio_all_tables + where relname like '%stats_partition%' + order by relname COLLATE "C"; + +SET enable_seqscan TO on; +SET enable_bitmapscan TO on; + ---- -- Basic tests for track_functions --- @@ -492,40 +563,40 @@ CREATE index stats_test_idx1 on stats_test_tab1(a); SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset SET enable_seqscan TO off; select a from stats_test_tab1 where a = 3; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); -- pg_stat_have_stats returns false for dropped index with stats -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); DROP index stats_test_idx1; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); -- pg_stat_have_stats returns false for rolled back index creation BEGIN; CREATE index stats_test_idx1 on stats_test_tab1(a); SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset select a from stats_test_tab1 where a = 3; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); ROLLBACK; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); -- pg_stat_have_stats returns true for reindex CONCURRENTLY CREATE index stats_test_idx1 on stats_test_tab1(a); SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset select a from stats_test_tab1 where a = 3; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); REINDEX index CONCURRENTLY stats_test_idx1; -- false for previous oid -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); -- true for new oid SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); -- pg_stat_have_stats returns true for a rolled back drop index with stats BEGIN; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); DROP index stats_test_idx1; ROLLBACK; -SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid); +SELECT pg_stat_have_stats('index', :dboid, :stats_test_idx1_oid); -- put enable_seqscan back to on SET enable_seqscan TO on; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 2f02cc8f42..38806d5dee 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2009,10 +2009,11 @@ PgStatShared_Common PgStatShared_Database PgStatShared_Function PgStatShared_HashEntry -PgStatShared_Relation +PgStatShared_Index PgStatShared_ReplSlot PgStatShared_SLRU PgStatShared_Subscription +PgStatShared_Table PgStatShared_Wal PgStat_ArchiverStats PgStat_BackendFunctionEntry