diff --git a/contrib/pgstattuple/pgstattuple--1.1--1.2.sql b/contrib/pgstattuple/pgstattuple--1.1--1.2.sql index 2783a63..8ebec6f 100644 --- a/contrib/pgstattuple/pgstattuple--1.1--1.2.sql +++ b/contrib/pgstattuple/pgstattuple--1.1--1.2.sql @@ -37,3 +37,17 @@ CREATE FUNCTION pg_relpages(IN relname regclass) RETURNS BIGINT AS 'MODULE_PATHNAME', 'pg_relpagesbyid' LANGUAGE C STRICT; + +CREATE FUNCTION pgstattuple2(IN relname regclass, + OUT table_len BIGINT, -- physical table length in bytes + OUT tuple_count BIGINT, -- number of live tuples + OUT tuple_len BIGINT, -- total tuples length in bytes + OUT tuple_percent FLOAT8, -- live tuples in % + OUT dead_tuple_count BIGINT, -- number of dead tuples + OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes + OUT dead_tuple_percent FLOAT8, -- dead tuples in % + OUT free_space BIGINT, -- free space in bytes + OUT free_percent FLOAT8) -- free space in % +AS 'MODULE_PATHNAME', 'pgstattuple2' +LANGUAGE C STRICT; + diff --git a/contrib/pgstattuple/pgstattuple--1.2.sql b/contrib/pgstattuple/pgstattuple--1.2.sql index e5fa2f5..963eb00 100644 --- a/contrib/pgstattuple/pgstattuple--1.2.sql +++ b/contrib/pgstattuple/pgstattuple--1.2.sql @@ -77,3 +77,17 @@ CREATE FUNCTION pg_relpages(IN relname regclass) RETURNS BIGINT AS 'MODULE_PATHNAME', 'pg_relpagesbyid' LANGUAGE C STRICT; + +CREATE FUNCTION pgstattuple2(IN relname regclass, + OUT table_len BIGINT, -- physical table length in bytes + OUT tuple_count BIGINT, -- number of live tuples + OUT tuple_len BIGINT, -- total tuples length in bytes + OUT tuple_percent FLOAT8, -- live tuples in % + OUT dead_tuple_count BIGINT, -- number of dead tuples + OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes + OUT dead_tuple_percent FLOAT8, -- dead tuples in % + OUT free_space BIGINT, -- free space in bytes + OUT free_percent FLOAT8) -- free space in % +AS 'MODULE_PATHNAME', 'pgstattuple2' +LANGUAGE C STRICT; + diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index f9ba0a6..2b29d44 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -41,9 +41,22 @@ PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(pgstattuple); PG_FUNCTION_INFO_V1(pgstattuplebyid); +PG_FUNCTION_INFO_V1(pgstattuple2); extern Datum pgstattuple(PG_FUNCTION_ARGS); extern Datum pgstattuplebyid(PG_FUNCTION_ARGS); +extern Datum pgstattuple2(PG_FUNCTION_ARGS); + +#define SAMPLE_SIZE 3000 + +typedef struct pgstattuple_block_stats +{ + uint64 tuple_count; + uint64 tuple_len; + uint64 dead_tuple_count; + uint64 dead_tuple_len; + uint64 free_space; /* free/reusable space in bytes */ +} pgstattuple_block_stats; /* * struct pgstattuple_type @@ -66,8 +79,9 @@ typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber, static Datum build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo); -static Datum pgstat_relation(Relation rel, FunctionCallInfo fcinfo); +static Datum pgstat_relation(Relation rel, FunctionCallInfo fcinfo, bool enable_sample); static Datum pgstat_heap(Relation rel, FunctionCallInfo fcinfo); +static Datum pgstat_heap_sample(Relation rel, FunctionCallInfo fcinfo); static void pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, BufferAccessStrategy bstrategy); @@ -81,6 +95,11 @@ static Datum pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn, FunctionCallInfo fcinfo); static void pgstat_index_page(pgstattuple_type *stat, Page page, OffsetNumber minoff, OffsetNumber maxoff); +static void compute_parameters(pgstattuple_block_stats *block_stats, + BlockNumber sample_size, BlockNumber nblocks, + uint64 *tuple_count, uint64 *tuple_len, + uint64 *dead_tuple_count, uint64 *dead_tuple_len, + uint64 *free_space); /* * build_pgstattuple_type -- build a pgstattuple_type tuple @@ -175,7 +194,7 @@ pgstattuple(PG_FUNCTION_ARGS) relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); - PG_RETURN_DATUM(pgstat_relation(rel, fcinfo)); + PG_RETURN_DATUM(pgstat_relation(rel, fcinfo, false)); } Datum @@ -192,14 +211,14 @@ pgstattuplebyid(PG_FUNCTION_ARGS) /* open relation */ rel = relation_open(relid, AccessShareLock); - PG_RETURN_DATUM(pgstat_relation(rel, fcinfo)); + PG_RETURN_DATUM(pgstat_relation(rel, fcinfo, false)); } /* * pgstat_relation */ static Datum -pgstat_relation(Relation rel, FunctionCallInfo fcinfo) +pgstat_relation(Relation rel, FunctionCallInfo fcinfo, bool enable_sample) { const char *err; @@ -219,6 +238,9 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo) case RELKIND_MATVIEW: case RELKIND_TOASTVALUE: case RELKIND_SEQUENCE: + if ( enable_sample ) + return pgstat_heap_sample(rel, fcinfo); + return pgstat_heap(rel, fcinfo); case RELKIND_INDEX: switch (rel->rd_rel->relam) @@ -537,3 +559,235 @@ pgstat_index_page(pgstattuple_type *stat, Page page, } } } + +static void +compute_parameters(pgstattuple_block_stats *block_stats, BlockNumber sample_size, BlockNumber nblocks, + uint64 *tuple_count, uint64 *tuple_len, + uint64 *dead_tuple_count, uint64 *dead_tuple_len, + uint64 *free_space) +{ + double tuple_count_avg; + double tuple_len_avg; + double dead_tuple_count_avg; + double dead_tuple_len_avg; + double free_space_avg; + + double tuple_count_sd; + double tuple_len_sd; + double dead_tuple_count_sd; + double dead_tuple_len_sd; + double free_space_sd; + + double tuple_count_se; + double tuple_len_se; + double dead_tuple_count_se; + double dead_tuple_len_se; + double free_space_se; + + int i; + + /* + * sample average + */ + tuple_count_avg = 0; + tuple_len_avg = 0; + dead_tuple_count_avg = 0; + dead_tuple_len_avg = 0; + free_space_avg = 0; + + for (i=0 ; i