mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add pgstatginindex() function to get the size of the GIN pending list.
Fujii Masao, reviewed by Kyotaro Horiguchi.
This commit is contained in:
@ -4,7 +4,7 @@ MODULE_big = pgstattuple
|
|||||||
OBJS = pgstattuple.o pgstatindex.o
|
OBJS = pgstattuple.o pgstatindex.o
|
||||||
|
|
||||||
EXTENSION = pgstattuple
|
EXTENSION = pgstattuple
|
||||||
DATA = pgstattuple--1.0.sql pgstattuple--unpackaged--1.0.sql
|
DATA = pgstattuple--1.1.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql
|
||||||
|
|
||||||
REGRESS = pgstattuple
|
REGRESS = pgstattuple
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ CREATE EXTENSION pgstattuple;
|
|||||||
-- the pgstattuple functions, but the results for empty tables and
|
-- the pgstattuple functions, but the results for empty tables and
|
||||||
-- indexes should be that.
|
-- indexes should be that.
|
||||||
--
|
--
|
||||||
create table test (a int primary key);
|
create table test (a int primary key, b int[]);
|
||||||
select * from pgstattuple('test'::text);
|
select * from pgstattuple('test'::text);
|
||||||
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
|
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
|
||||||
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
|
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
|
||||||
@ -35,3 +35,10 @@ select pg_relpages('test_pkey');
|
|||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
create index test_ginidx on test using gin (b);
|
||||||
|
select * from pgstatginindex('test_ginidx');
|
||||||
|
version | pending_pages | pending_tuples
|
||||||
|
---------+---------------+----------------
|
||||||
|
1 | 0 | 0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -27,7 +27,9 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/gin_private.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
|
#include "access/htup_details.h"
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
@ -39,12 +41,15 @@
|
|||||||
|
|
||||||
extern Datum pgstatindex(PG_FUNCTION_ARGS);
|
extern Datum pgstatindex(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_relpages(PG_FUNCTION_ARGS);
|
extern Datum pg_relpages(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum pgstatginindex(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(pgstatindex);
|
PG_FUNCTION_INFO_V1(pgstatindex);
|
||||||
PG_FUNCTION_INFO_V1(pg_relpages);
|
PG_FUNCTION_INFO_V1(pg_relpages);
|
||||||
|
PG_FUNCTION_INFO_V1(pgstatginindex);
|
||||||
|
|
||||||
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
|
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
|
||||||
#define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
|
#define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
|
||||||
|
#define IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID)
|
||||||
|
|
||||||
#define CHECK_PAGE_OFFSET_RANGE(pg, offnum) { \
|
#define CHECK_PAGE_OFFSET_RANGE(pg, offnum) { \
|
||||||
if ( !(FirstOffsetNumber <= (offnum) && \
|
if ( !(FirstOffsetNumber <= (offnum) && \
|
||||||
@ -79,6 +84,19 @@ typedef struct BTIndexStat
|
|||||||
uint64 fragments;
|
uint64 fragments;
|
||||||
} BTIndexStat;
|
} BTIndexStat;
|
||||||
|
|
||||||
|
/* ------------------------------------------------
|
||||||
|
* A structure for a whole GIN index statistics
|
||||||
|
* used by pgstatginindex().
|
||||||
|
* ------------------------------------------------
|
||||||
|
*/
|
||||||
|
typedef struct GinIndexStat
|
||||||
|
{
|
||||||
|
int32 version;
|
||||||
|
|
||||||
|
BlockNumber pending_pages;
|
||||||
|
int64 pending_tuples;
|
||||||
|
} GinIndexStat;
|
||||||
|
|
||||||
/* ------------------------------------------------------
|
/* ------------------------------------------------------
|
||||||
* pgstatindex()
|
* pgstatindex()
|
||||||
*
|
*
|
||||||
@ -292,3 +310,79 @@ pg_relpages(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_INT64(relpages);
|
PG_RETURN_INT64(relpages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------
|
||||||
|
* pgstatginindex()
|
||||||
|
*
|
||||||
|
* Usage: SELECT * FROM pgstatginindex('ginindex');
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pgstatginindex(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid relid = PG_GETARG_OID(0);
|
||||||
|
Relation rel;
|
||||||
|
Buffer buffer;
|
||||||
|
Page page;
|
||||||
|
GinMetaPageData *metadata;
|
||||||
|
GinIndexStat stats;
|
||||||
|
HeapTuple tuple;
|
||||||
|
TupleDesc tupleDesc;
|
||||||
|
Datum values[3];
|
||||||
|
bool nulls[3] = {false, false, false};
|
||||||
|
Datum result;
|
||||||
|
|
||||||
|
if (!superuser())
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
|
(errmsg("must be superuser to use pgstattuple functions"))));
|
||||||
|
|
||||||
|
rel = relation_open(relid, AccessShareLock);
|
||||||
|
|
||||||
|
if (!IS_INDEX(rel) || !IS_GIN(rel))
|
||||||
|
elog(ERROR, "relation \"%s\" is not a GIN index",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reject attempts to read non-local temporary relations; we would be
|
||||||
|
* likely to get wrong data since we have no visibility into the owning
|
||||||
|
* session's local buffers.
|
||||||
|
*/
|
||||||
|
if (RELATION_IS_OTHER_TEMP(rel))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("cannot access temporary indexes of other sessions")));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read metapage
|
||||||
|
*/
|
||||||
|
buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO);
|
||||||
|
LockBuffer(buffer, GIN_SHARE);
|
||||||
|
page = BufferGetPage(buffer);
|
||||||
|
metadata = GinPageGetMeta(page);
|
||||||
|
|
||||||
|
stats.version = metadata->ginVersion;
|
||||||
|
stats.pending_pages = metadata->nPendingPages;
|
||||||
|
stats.pending_tuples = metadata->nPendingHeapTuples;
|
||||||
|
|
||||||
|
UnlockReleaseBuffer(buffer);
|
||||||
|
relation_close(rel, AccessShareLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build a tuple descriptor for our result type
|
||||||
|
*/
|
||||||
|
if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
|
||||||
|
elog(ERROR, "return type must be a row type");
|
||||||
|
|
||||||
|
values[0] = Int32GetDatum(stats.version);
|
||||||
|
values[1] = UInt32GetDatum(stats.pending_pages);
|
||||||
|
values[2] = Int64GetDatum(stats.pending_tuples);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build and return the tuple
|
||||||
|
*/
|
||||||
|
tuple = heap_form_tuple(tupleDesc, values, nulls);
|
||||||
|
result = HeapTupleGetDatum(tuple);
|
||||||
|
|
||||||
|
PG_RETURN_DATUM(result);
|
||||||
|
}
|
||||||
|
11
contrib/pgstattuple/pgstattuple--1.0--1.1.sql
Normal file
11
contrib/pgstattuple/pgstattuple--1.0--1.1.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* contrib/pgstattuple/pgstattuple--1.0--1.1.sql */
|
||||||
|
|
||||||
|
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION pgstattuple UPDATE TO '1.1'" to load this file. \quit
|
||||||
|
|
||||||
|
CREATE FUNCTION pgstatginindex(IN relname regclass,
|
||||||
|
OUT version INT4,
|
||||||
|
OUT pending_pages INT4,
|
||||||
|
OUT pending_tuples BIGINT)
|
||||||
|
AS 'MODULE_PATHNAME', 'pgstatginindex'
|
||||||
|
LANGUAGE C STRICT;
|
@ -1,4 +1,4 @@
|
|||||||
/* contrib/pgstattuple/pgstattuple--1.0.sql */
|
/* contrib/pgstattuple/pgstattuple--1.1.sql */
|
||||||
|
|
||||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
|
\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
|
||||||
@ -47,3 +47,12 @@ CREATE FUNCTION pg_relpages(IN relname text)
|
|||||||
RETURNS BIGINT
|
RETURNS BIGINT
|
||||||
AS 'MODULE_PATHNAME', 'pg_relpages'
|
AS 'MODULE_PATHNAME', 'pg_relpages'
|
||||||
LANGUAGE C STRICT;
|
LANGUAGE C STRICT;
|
||||||
|
|
||||||
|
/* New stuff in 1.1 begins here */
|
||||||
|
|
||||||
|
CREATE FUNCTION pgstatginindex(IN relname regclass,
|
||||||
|
OUT version INT4,
|
||||||
|
OUT pending_pages INT4,
|
||||||
|
OUT pending_tuples BIGINT)
|
||||||
|
AS 'MODULE_PATHNAME', 'pgstatginindex'
|
||||||
|
LANGUAGE C STRICT;
|
@ -1,5 +1,5 @@
|
|||||||
# pgstattuple extension
|
# pgstattuple extension
|
||||||
comment = 'show tuple-level statistics'
|
comment = 'show tuple-level statistics'
|
||||||
default_version = '1.0'
|
default_version = '1.1'
|
||||||
module_pathname = '$libdir/pgstattuple'
|
module_pathname = '$libdir/pgstattuple'
|
||||||
relocatable = true
|
relocatable = true
|
||||||
|
@ -6,7 +6,7 @@ CREATE EXTENSION pgstattuple;
|
|||||||
-- indexes should be that.
|
-- indexes should be that.
|
||||||
--
|
--
|
||||||
|
|
||||||
create table test (a int primary key);
|
create table test (a int primary key, b int[]);
|
||||||
|
|
||||||
select * from pgstattuple('test'::text);
|
select * from pgstattuple('test'::text);
|
||||||
select * from pgstattuple('test'::regclass);
|
select * from pgstattuple('test'::regclass);
|
||||||
@ -15,3 +15,7 @@ select * from pgstatindex('test_pkey');
|
|||||||
|
|
||||||
select pg_relpages('test');
|
select pg_relpages('test');
|
||||||
select pg_relpages('test_pkey');
|
select pg_relpages('test_pkey');
|
||||||
|
|
||||||
|
create index test_ginidx on test using gin (b);
|
||||||
|
|
||||||
|
select * from pgstatginindex('test_ginidx');
|
||||||
|
@ -244,6 +244,63 @@ leaf_fragmentation | 0
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<function>pgstatginindex(regclass) returns record</>
|
||||||
|
</term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<function>pgstatginindex</function> returns a record showing information
|
||||||
|
about a GIN index. For example:
|
||||||
|
<programlisting>
|
||||||
|
test=> SELECT * FROM pgstatginindex('test_gin_index');
|
||||||
|
-[ RECORD 1 ]--+--
|
||||||
|
version | 1
|
||||||
|
pending_pages | 0
|
||||||
|
pending_tuples | 0
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The output columns are:
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="3">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Column</entry>
|
||||||
|
<entry>Type</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry><structfield>version</structfield></entry>
|
||||||
|
<entry><type>integer</type></entry>
|
||||||
|
<entry>GIN version number</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>pending_pages</structfield></entry>
|
||||||
|
<entry><type>integer</type></entry>
|
||||||
|
<entry>Number of pages in the pending list</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>pending_tuples</structfield></entry>
|
||||||
|
<entry><type>bigint</type></entry>
|
||||||
|
<entry>Number of tuples in the pending list</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<function>pg_relpages(text) returns bigint</>
|
<function>pg_relpages(text) returns bigint</>
|
||||||
|
Reference in New Issue
Block a user