Re: pgstattuple extension for indexes - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: pgstattuple extension for indexes |
Date | |
Msg-id | 200609040349.k843nDv09463@momjian.us Whole thread Raw |
In response to | Re: pgstattuple extension for indexes (Satoshi Nagayasu <nagayasus@nttdata.co.jp>) |
List | pgsql-patches |
Applied. --------------------------------------------------------------------------- Satoshi Nagayasu wrote: > Thanks Bruce, > > Here are updated Japanese README, and uninstall_pgstattuple.sql. > > Bruce Momjian wrote: > > Patch applied. Thanks. > > > > I updated the README documentation for the new functions, attached. I > > could not update the Japanese version of the README. > > > > --------------------------------------------------------------------------- > > > > > > Satoshi Nagayasu wrote: > >> Bruce, > >> > >> Attached patch has been cleaned up, > >> and modified to be able to work with CVS HEAD. > >> > >> Thanks. > >> > >> Satoshi Nagayasu wrote: > >>> Alvaro, > >>> > >>> Alvaro Herrera wrote: > >>>> Huh, I bet it works with 8.1.4, but it doesn't work on CVS HEAD: > >>>> > >>>> /pgsql/source/00orig/contrib/pgstattuple/pgstatindex.c: In function 'GetBTPageStatistics': > >>>> /pgsql/source/00orig/contrib/pgstattuple/pgstatindex.c:182: error: 'BTItem' undeclared (first use in this function) > >>>> > >>>> > >>>> While you're at it, please consider removing C++ style comments and > >>>> unused code. > >>>> > >>>> Formatting is way off as well, but I guess that is easily fixed with > >>>> pgindent. > >>> Thanks for comments. I'm going to fix my patch from now. > >>> > >>>> Regarding the pg_relpages function, why do you think it's necessary? > >>>> (It returns the true number of blocks of a given relation). It may > >>>> belong into core given a reasonable use case, but otherwise it doesn't > >>>> seem to belong into pgstatindex (or pgstattuple for that matter). > >>> I wanted to sample some pages from the table/index, and get their statistics > >>> to know table/index conditions. I know pgstattuple() reports table > >>> statistics, however, pgstattuple() generates heavy CPU and I/O load. > >>> > >>> When we need to sample some pages from table/index, we need to know > >>> true number of blocks. > >>> > >>> I have another function, called pgstatpage(), to get information inside > >>> a single block/page statistics of the table. pg_relpages() will be used > >>> with this. > >>> > >>> Sorry for not mentioned in previous post about pgstatpage(), > >>> but I've remembered about it just now. > >>> > >>> Many memories in my brain have already `paged-out` (too busy in last few months), > >>> and some of them got `out-of-memory`. :^) > >>> > >>> Thanks. > >> > >> -- > >> NAGAYASU Satoshi <nagayasus@nttdata.co.jp> > >> Phone: +81-3-3523-8122 > > > >> diff -ruN pgstattuple.orig/Makefile pgstattuple/Makefile > >> --- pgstattuple.orig/Makefile 2006-02-27 21:54:40.000000000 +0900 > >> +++ pgstattuple/Makefile 2006-08-14 09:28:58.000000000 +0900 > >> @@ -6,7 +6,7 @@ > >> # > >> #------------------------------------------------------------------------- > >> > >> -SRCS = pgstattuple.c > >> +SRCS = pgstattuple.c pgstatindex.c > >> > >> MODULE_big = pgstattuple > >> OBJS = $(SRCS:.c=.o) > >> diff -ruN pgstattuple.orig/pgstatindex.c pgstattuple/pgstatindex.c > >> --- pgstattuple.orig/pgstatindex.c 1970-01-01 09:00:00.000000000 +0900 > >> +++ pgstattuple/pgstatindex.c 2006-08-14 11:24:23.000000000 +0900 > >> @@ -0,0 +1,706 @@ > >> +/* > >> + * pgstatindex > >> + * > >> + * Copyright (c) 2006 Satoshi Nagayasu <nagayasus@nttdata.co.jp> > >> + * > >> + * Permission to use, copy, modify, and distribute this software and > >> + * its documentation for any purpose, without fee, and without a > >> + * written agreement is hereby granted, provided that the above > >> + * copyright notice and this paragraph and the following two > >> + * paragraphs appear in all copies. > >> + * > >> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, > >> + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING > >> + * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS > >> + * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED > >> + * OF THE POSSIBILITY OF SUCH DAMAGE. > >> + * > >> + * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT > >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > >> + * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS > >> + * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, > >> + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. > >> + */ > >> + > >> +#include "postgres.h" > >> + > >> +#include "fmgr.h" > >> +#include "funcapi.h" > >> +#include "access/heapam.h" > >> +#include "access/itup.h" > >> +#include "access/nbtree.h" > >> +#include "access/transam.h" > >> +#include "catalog/namespace.h" > >> +#include "catalog/pg_type.h" > >> +#include "utils/builtins.h" > >> +#include "utils/inval.h" > >> + > >> +PG_FUNCTION_INFO_V1(pgstatindex); > >> +PG_FUNCTION_INFO_V1(bt_metap); > >> +PG_FUNCTION_INFO_V1(bt_page_items); > >> +PG_FUNCTION_INFO_V1(bt_page_stats); > >> +PG_FUNCTION_INFO_V1(pg_relpages); > >> + > >> +extern Datum pgstatindex(PG_FUNCTION_ARGS); > >> +extern Datum bt_metap(PG_FUNCTION_ARGS); > >> +extern Datum bt_page_items(PG_FUNCTION_ARGS); > >> +extern Datum bt_page_stats(PG_FUNCTION_ARGS); > >> +extern Datum pg_relpages(PG_FUNCTION_ARGS); > >> + > >> +#define PGSTATINDEX_TYPE "public.pgstatindex_type" > >> +#define PGSTATINDEX_NCOLUMNS 10 > >> + > >> +#define BTMETAP_TYPE "public.bt_metap_type" > >> +#define BTMETAP_NCOLUMNS 6 > >> + > >> +#define BTPAGEITEMS_TYPE "public.bt_page_items_type" > >> +#define BTPAGEITEMS_NCOLUMNS 6 > >> + > >> +#define BTPAGESTATS_TYPE "public.bt_page_stats_type" > >> +#define BTPAGESTATS_NCOLUMNS 11 > >> + > >> + > >> +#define IS_INDEX(r) ((r)->rd_rel->relkind == 'i') > >> +#define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID) > >> + > >> +#define CHECK_PAGE_OFFSET_RANGE(page, offset) { \ > >> + if ( !(FirstOffsetNumber<=(offset) && \ > >> + (offset)<=PageGetMaxOffsetNumber(page)) ) \ > >> + elog(ERROR, "Page offset number out of range."); } > >> + > >> +#define CHECK_RELATION_BLOCK_RANGE(rel, blkno) { \ > >> + if ( (blkno)<0 && RelationGetNumberOfBlocks((rel))<=(blkno) ) \ > >> + elog(ERROR, "Block number out of range."); } > >> + > >> +/* ------------------------------------------------ > >> + * structure for single btree page statistics > >> + * ------------------------------------------------ > >> + */ > >> +typedef struct BTPageStat > >> +{ > >> + uint32 blkno; > >> + uint32 live_items; > >> + uint32 dead_items; > >> + uint32 page_size; > >> + uint32 max_avail; > >> + uint32 free_size; > >> + uint32 avg_item_size; > >> + uint32 fragments; > >> + char type; > >> + > >> + /* opaque data */ > >> + BlockNumber btpo_prev; > >> + BlockNumber btpo_next; > >> + union > >> + { > >> + uint32 level; > >> + TransactionId xact; > >> + } btpo; > >> + uint16 btpo_flags; > >> + BTCycleId btpo_cycleid; > >> +} BTPageStat; > >> + > >> +/* ------------------------------------------------ > >> + * A structure for a whole btree index statistics > >> + * used by pgstatindex(). > >> + * ------------------------------------------------ > >> + */ > >> +typedef struct BTIndexStat > >> +{ > >> + uint32 magic; > >> + uint32 version; > >> + BlockNumber root_blkno; > >> + uint32 level; > >> + > >> + BlockNumber fastroot; > >> + uint32 fastlevel; > >> + > >> + uint32 live_items; > >> + uint32 dead_items; > >> + > >> + uint32 root_pages; > >> + uint32 internal_pages; > >> + uint32 leaf_pages; > >> + uint32 empty_pages; > >> + uint32 deleted_pages; > >> + > >> + uint32 page_size; > >> + uint32 avg_item_size; > >> + > >> + uint32 max_avail; > >> + uint32 free_space; > >> + > >> + uint32 fragments; > >> +} BTIndexStat; > >> + > >> +/* ------------------------------------------------- > >> + * GetBTPageStatistics() > >> + * > >> + * Collect statistics of single b-tree leaf page > >> + * ------------------------------------------------- > >> + */ > >> +static bool > >> +GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat * stat) > >> +{ > >> + Page page = BufferGetPage(buffer); > >> + PageHeader phdr = (PageHeader) page; > >> + OffsetNumber maxoff = PageGetMaxOffsetNumber(page); > >> + BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page); > >> + int item_size = 0; > >> + int off; > >> + > >> + stat->blkno = blkno; > >> + > >> + stat->max_avail = BLCKSZ - (BLCKSZ - phdr->pd_special + SizeOfPageHeaderData); > >> + > >> + stat->dead_items = stat->live_items = 0; > >> + > >> + stat->page_size = PageGetPageSize(page); > >> + > >> + /* page type (flags) */ > >> + if (P_ISDELETED(opaque)) > >> + { > >> + stat->type = 'd'; > >> + return true; > >> + } > >> + else if (P_IGNORE(opaque)) > >> + stat->type = 'e'; > >> + else if (P_ISLEAF(opaque)) > >> + stat->type = 'l'; > >> + else if (P_ISROOT(opaque)) > >> + stat->type = 'r'; > >> + else > >> + stat->type = 'i'; > >> + > >> + /* btpage opaque data */ > >> + stat->btpo_prev = opaque->btpo_prev; > >> + stat->btpo_next = opaque->btpo_next; > >> + if (P_ISDELETED(opaque)) > >> + stat->btpo.xact = opaque->btpo.xact; > >> + else > >> + stat->btpo.level = opaque->btpo.level; > >> + stat->btpo_flags = opaque->btpo_flags; > >> + stat->btpo_cycleid = opaque->btpo_cycleid; > >> + > >> + /*---------------------------------------------- > >> + * If a next leaf is on the previous block, > >> + * it means a fragmentation. > >> + *---------------------------------------------- > >> + */ > >> + stat->fragments = 0; > >> + if (stat->type == 'l') > >> + { > >> + if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno) > >> + stat->fragments++; > >> + } > >> + > >> + /* count live and dead tuples, and free space */ > >> + for (off = FirstOffsetNumber; off <= maxoff; off++) > >> + { > >> + IndexTuple itup; > >> + > >> + ItemId id = PageGetItemId(page, off); > >> + > >> + itup = (IndexTuple) PageGetItem(page, id); > >> + > >> + item_size += IndexTupleSize(itup); > >> + > >> + if (!ItemIdDeleted(id)) > >> + stat->live_items++; > >> + else > >> + stat->dead_items++; > >> + } > >> + stat->free_size = PageGetFreeSpace(page); > >> + > >> + if ((stat->live_items + stat->dead_items) > 0) > >> + stat->avg_item_size = item_size / (stat->live_items + stat->dead_items); > >> + else > >> + stat->avg_item_size = 0; > >> + > >> + return true; > >> +} > >> + > >> + > >> +/* ------------------------------------------------------ > >> + * pgstatindex() > >> + * > >> + * Usage: SELECT * FROM pgstatindex('t1_pkey'); > >> + * ------------------------------------------------------ > >> + */ > >> +Datum > >> +pgstatindex(PG_FUNCTION_ARGS) > >> +{ > >> + text *relname = PG_GETARG_TEXT_P(0); > >> + Relation rel; > >> + RangeVar *relrv; > >> + Datum result; > >> + uint32 nblocks; > >> + uint32 blkno; > >> + BTIndexStat indexStat; > >> + > >> + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); > >> + rel = relation_openrv(relrv, AccessShareLock); > >> + > >> + if (!IS_INDEX(rel) || !IS_BTREE(rel)) > >> + elog(ERROR, "pgstatindex() can be used only on b-tree index."); > >> + > >> + /*------------------- > >> + * Read a metapage > >> + *------------------- > >> + */ > >> + { > >> + Buffer buffer = ReadBuffer(rel, 0); > >> + Page page = BufferGetPage(buffer); > >> + BTMetaPageData *metad = BTPageGetMeta(page); > >> + > >> + indexStat.magic = metad->btm_magic; > >> + indexStat.version = metad->btm_version; > >> + indexStat.root_blkno = metad->btm_root; > >> + indexStat.level = metad->btm_level; > >> + indexStat.fastroot = metad->btm_fastroot; > >> + indexStat.fastlevel = metad->btm_fastlevel; > >> + > >> + ReleaseBuffer(buffer); > >> + } > >> + > >> + nblocks = RelationGetNumberOfBlocks(rel); > >> + > >> + /* -- init stat -- */ > >> + indexStat.fragments = 0; > >> + > >> + indexStat.root_pages = 0; > >> + indexStat.leaf_pages = 0; > >> + indexStat.internal_pages = 0; > >> + indexStat.empty_pages = 0; > >> + indexStat.deleted_pages = 0; > >> + > >> + indexStat.max_avail = 0; > >> + indexStat.free_space = 0; > >> + > >> + /*----------------------- > >> + * Scan all blocks > >> + *----------------------- > >> + */ > >> + for (blkno = 1; blkno < nblocks; blkno++) > >> + { > >> + Buffer buffer = ReadBuffer(rel, blkno); > >> + BTPageStat stat; > >> + > >> + /* scan one page */ > >> + stat.blkno = blkno; > >> + GetBTPageStatistics(blkno, buffer, &stat); > >> + > >> + /*--------------------- > >> + * page status (type) > >> + *--------------------- > >> + */ > >> + switch (stat.type) > >> + { > >> + case 'd': > >> + indexStat.deleted_pages++; > >> + break; > >> + case 'l': > >> + indexStat.leaf_pages++; > >> + break; > >> + case 'i': > >> + indexStat.internal_pages++; > >> + break; > >> + case 'e': > >> + indexStat.empty_pages++; > >> + break; > >> + case 'r': > >> + indexStat.root_pages++; > >> + break; > >> + default: > >> + elog(ERROR, "unknown page status."); > >> + } > >> + > >> + /* -- leaf fragmentation -- */ > >> + indexStat.fragments += stat.fragments; > >> + > >> + if (stat.type == 'l') > >> + { > >> + indexStat.max_avail += stat.max_avail; > >> + indexStat.free_space += stat.free_size; > >> + } > >> + > >> + ReleaseBuffer(buffer); > >> + } > >> + > >> + relation_close(rel, AccessShareLock); > >> + > >> + /*---------------------------- > >> + * Build a result tuple > >> + *---------------------------- > >> + */ > >> + { > >> + TupleDesc tupleDesc; > >> + int j; > >> + char *values[PGSTATINDEX_NCOLUMNS]; > >> + > >> + HeapTupleData tupleData; > >> + HeapTuple tuple = &tupleData; > >> + > >> + tupleDesc = RelationNameGetTupleDesc(PGSTATINDEX_TYPE); > >> + > >> + j = 0; > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.version); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.level); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", (indexStat.root_pages + > >> + indexStat.leaf_pages + > >> + indexStat.internal_pages + > >> + indexStat.deleted_pages + > >> + indexStat.empty_pages) * BLCKSZ); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.root_blkno); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.internal_pages); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.leaf_pages); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.empty_pages); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", indexStat.deleted_pages); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%.2f", 100.0 - (float) indexStat.free_space / (float) indexStat.max_avail * 100.0); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%.2f", (float) indexStat.fragments / (float) indexStat.leaf_pages * 100.0); > >> + > >> + tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), > >> + values); > >> + > >> + result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); > >> + } > >> + > >> + PG_RETURN_DATUM(result); > >> +} > >> + > >> +/* ----------------------------------------------- > >> + * bt_page() > >> + * > >> + * Usage: SELECT * FROM bt_page('t1_pkey', 0); > >> + * ----------------------------------------------- > >> + */ > >> +Datum > >> +bt_page_stats(PG_FUNCTION_ARGS) > >> +{ > >> + text *relname = PG_GETARG_TEXT_P(0); > >> + uint32 blkno = PG_GETARG_UINT32(1); > >> + Buffer buffer; > >> + > >> + Relation rel; > >> + RangeVar *relrv; > >> + Datum result; > >> + > >> + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); > >> + rel = relation_openrv(relrv, AccessShareLock); > >> + > >> + CHECK_RELATION_BLOCK_RANGE(rel, blkno); > >> + > >> + buffer = ReadBuffer(rel, blkno); > >> + > >> + if (!IS_INDEX(rel) || !IS_BTREE(rel)) > >> + elog(ERROR, "bt_page_stats() can be used only on b-tree index."); > >> + > >> + if (blkno == 0) > >> + elog(ERROR, "Block 0 is a meta page."); > >> + > >> + { > >> + HeapTuple tuple; > >> + TupleDesc tupleDesc; > >> + int j; > >> + char *values[BTPAGESTATS_NCOLUMNS]; > >> + > >> + BTPageStat stat; > >> + > >> + GetBTPageStatistics(blkno, buffer, &stat); > >> + > >> + tupleDesc = RelationNameGetTupleDesc(BTPAGESTATS_TYPE); > >> + > >> + j = 0; > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.blkno); > >> + > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%c", stat.type); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.live_items); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.dead_items); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.avg_item_size); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.page_size); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.free_size); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.btpo_prev); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.btpo_next); > >> + > >> + values[j] = palloc(32); > >> + if (stat.type == 'd') > >> + snprintf(values[j++], 32, "%d", stat.btpo.xact); > >> + else > >> + snprintf(values[j++], 32, "%d", stat.btpo.level); > >> + > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", stat.btpo_flags); > >> + > >> + tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), > >> + values); > >> + > >> + result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); > >> + } > >> + > >> + ReleaseBuffer(buffer); > >> + > >> + relation_close(rel, AccessShareLock); > >> + > >> + PG_RETURN_DATUM(result); > >> +} > >> + > >> +/*------------------------------------------------------- > >> + * bt_page_items() > >> + * > >> + * Get IndexTupleData set in a leaf page > >> + * > >> + * Usage: SELECT * FROM bt_page_items('t1_pkey', 0); > >> + *------------------------------------------------------- > >> + */ > >> +/* --------------------------------------------------- > >> + * data structure for SRF to hold a scan information > >> + * --------------------------------------------------- > >> + */ > >> +struct user_args > >> +{ > >> + TupleDesc tupd; > >> + Relation rel; > >> + Buffer buffer; > >> + Page page; > >> + uint16 offset; > >> +}; > >> + > >> +Datum > >> +bt_page_items(PG_FUNCTION_ARGS) > >> +{ > >> + text *relname = PG_GETARG_TEXT_P(0); > >> + uint32 blkno = PG_GETARG_UINT32(1); > >> + > >> + RangeVar *relrv; > >> + Datum result; > >> + char *values[BTPAGEITEMS_NCOLUMNS]; > >> + BTPageOpaque opaque; > >> + HeapTuple tuple; > >> + ItemId id; > >> + > >> + FuncCallContext *fctx; > >> + MemoryContext mctx; > >> + struct user_args *uargs = NULL; > >> + > >> + if (blkno == 0) > >> + elog(ERROR, "Block 0 is a meta page."); > >> + > >> + if (SRF_IS_FIRSTCALL()) > >> + { > >> + fctx = SRF_FIRSTCALL_INIT(); > >> + mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); > >> + > >> + uargs = palloc(sizeof(struct user_args)); > >> + > >> + uargs->tupd = RelationNameGetTupleDesc(BTPAGEITEMS_TYPE); > >> + uargs->offset = FirstOffsetNumber; > >> + > >> + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); > >> + uargs->rel = relation_openrv(relrv, AccessShareLock); > >> + > >> + CHECK_RELATION_BLOCK_RANGE(uargs->rel, blkno); > >> + > >> + uargs->buffer = ReadBuffer(uargs->rel, blkno); > >> + > >> + if (!IS_INDEX(uargs->rel) || !IS_BTREE(uargs->rel)) > >> + elog(ERROR, "bt_page_items() can be used only on b-tree index."); > >> + > >> + uargs->page = BufferGetPage(uargs->buffer); > >> + > >> + opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page); > >> + > >> + if (P_ISDELETED(opaque)) > >> + elog(NOTICE, "bt_page_items(): this page is deleted."); > >> + > >> + fctx->max_calls = PageGetMaxOffsetNumber(uargs->page); > >> + fctx->user_fctx = uargs; > >> + > >> + MemoryContextSwitchTo(mctx); > >> + } > >> + > >> + fctx = SRF_PERCALL_SETUP(); > >> + uargs = fctx->user_fctx; > >> + > >> + if (fctx->call_cntr < fctx->max_calls) > >> + { > >> + IndexTuple itup; > >> + > >> + id = PageGetItemId(uargs->page, uargs->offset); > >> + > >> + if (!ItemIdIsValid(id)) > >> + elog(ERROR, "Invalid ItemId."); > >> + > >> + itup = (IndexTuple) PageGetItem(uargs->page, id); > >> + > >> + { > >> + int j = 0; > >> + > >> + BlockNumber blkno = BlockIdGetBlockNumber(&(itup->t_tid.ip_blkid)); > >> + > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", uargs->offset); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "(%u,%u)", blkno, itup->t_tid.ip_posid); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", IndexTupleSize(itup)); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%c", IndexTupleHasNulls(itup) ? 't' : 'f'); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%c", IndexTupleHasVarwidths(itup) ? 't' : 'f'); > >> + > >> + { > >> + int off; > >> + char *dump; > >> + char *ptr = (char *) itup + IndexInfoFindDataOffset(itup->t_info); > >> + > >> + dump = palloc(IndexTupleSize(itup) * 3); > >> + memset(dump, 0, IndexTupleSize(itup) * 3); > >> + > >> + for (off = 0; > >> + off < IndexTupleSize(itup) - IndexInfoFindDataOffset(itup->t_info); > >> + off++) > >> + { > >> + if (dump[0] == '\0') > >> + sprintf(dump, "%02x", *(ptr + off) & 0xff); > >> + else > >> + { > >> + char buf[4]; > >> + > >> + sprintf(buf, " %02x", *(ptr + off) & 0xff); > >> + strcat(dump, buf); > >> + } > >> + } > >> + values[j] = dump; > >> + } > >> + > >> + tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(uargs->tupd), values); > >> + result = TupleGetDatum(TupleDescGetSlot(uargs->tupd), tuple); > >> + } > >> + > >> + uargs->offset = uargs->offset + 1; > >> + > >> + SRF_RETURN_NEXT(fctx, result); > >> + } > >> + else > >> + { > >> + ReleaseBuffer(uargs->buffer); > >> + relation_close(uargs->rel, AccessShareLock); > >> + > >> + SRF_RETURN_DONE(fctx); > >> + } > >> +} > >> + > >> + > >> +/* ------------------------------------------------ > >> + * bt_metap() > >> + * > >> + * Get a btree meta-page information > >> + * > >> + * Usage: SELECT * FROM bt_metap('t1_pkey') > >> + * ------------------------------------------------ > >> + */ > >> +Datum > >> +bt_metap(PG_FUNCTION_ARGS) > >> +{ > >> + text *relname = PG_GETARG_TEXT_P(0); > >> + Buffer buffer; > >> + > >> + Relation rel; > >> + RangeVar *relrv; > >> + Datum result; > >> + > >> + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); > >> + rel = relation_openrv(relrv, AccessShareLock); > >> + > >> + if (!IS_INDEX(rel) || !IS_BTREE(rel)) > >> + elog(ERROR, "bt_metap() can be used only on b-tree index."); > >> + > >> + buffer = ReadBuffer(rel, 0); > >> + > >> + { > >> + BTMetaPageData *metad; > >> + > >> + TupleDesc tupleDesc; > >> + int j; > >> + char *values[BTMETAP_NCOLUMNS]; > >> + HeapTuple tuple; > >> + > >> + Page page = BufferGetPage(buffer); > >> + > >> + metad = BTPageGetMeta(page); > >> + > >> + tupleDesc = RelationNameGetTupleDesc(BTMETAP_TYPE); > >> + > >> + j = 0; > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", metad->btm_magic); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", metad->btm_version); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", metad->btm_root); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", metad->btm_level); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", metad->btm_fastroot); > >> + values[j] = palloc(32); > >> + snprintf(values[j++], 32, "%d", metad->btm_fastlevel); > >> + > >> + tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), > >> + values); > >> + > >> + result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); > >> + } > >> + > >> + ReleaseBuffer(buffer); > >> + > >> + relation_close(rel, AccessShareLock); > >> + > >> + PG_RETURN_DATUM(result); > >> +} > >> + > >> +/* -------------------------------------------------------- > >> + * pg_relpages() > >> + * > >> + * Get a number of pages of the table/index. > >> + * > >> + * Usage: SELECT pg_relpages('t1'); > >> + * SELECT pg_relpages('t1_pkey'); > >> + * -------------------------------------------------------- > >> + */ > >> +Datum > >> +pg_relpages(PG_FUNCTION_ARGS) > >> +{ > >> + text *relname = PG_GETARG_TEXT_P(0); > >> + > >> + Relation rel; > >> + RangeVar *relrv; > >> + int4 relpages; > >> + > >> + relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); > >> + rel = relation_openrv(relrv, AccessShareLock); > >> + > >> + relpages = RelationGetNumberOfBlocks(rel); > >> + > >> + relation_close(rel, AccessShareLock); > >> + > >> + PG_RETURN_INT32(relpages); > >> +} > >> diff -ruN pgstattuple.orig/pgstattuple.sql.in pgstattuple/pgstattuple.sql.in > >> --- pgstattuple.orig/pgstattuple.sql.in 2006-02-28 01:09:50.000000000 +0900 > >> +++ pgstattuple/pgstattuple.sql.in 2006-08-14 10:37:32.000000000 +0900 > >> @@ -22,3 +22,96 @@ > >> RETURNS pgstattuple_type > >> AS 'MODULE_PATHNAME', 'pgstattuplebyid' > >> LANGUAGE C STRICT; > >> + > >> +-- > >> +-- pgstatindex > >> +-- > >> +DROP TYPE pgstatindex_type CASCADE; > >> +CREATE TYPE pgstatindex_type AS ( > >> + version int4, > >> + tree_level int4, > >> + index_size int4, > >> + root_block_no int4, > >> + internal_pages int4, > >> + leaf_pages int4, > >> + empty_pages int4, > >> + deleted_pages int4, > >> + avg_leaf_density float8, > >> + leaf_fragmentation float8 > >> +); > >> + > >> +CREATE OR REPLACE FUNCTION pgstatindex(text) > >> +RETURNS pgstatindex_type > >> +AS 'MODULE_PATHNAME', 'pgstatindex' > >> +LANGUAGE 'C' STRICT; > >> + > >> +-- > >> +-- bt_metap() > >> +-- > >> +DROP TYPE bt_metap_type CASCADE; > >> +CREATE TYPE bt_metap_type AS ( > >> + magic int4, > >> + version int4, > >> + root int4, > >> + level int4, > >> + fastroot int4, > >> + fastlevel int4 > >> +); > >> + > >> +CREATE OR REPLACE FUNCTION bt_metap(text) > >> +RETURNS bt_metap_type > >> +AS 'MODULE_PATHNAME', 'bt_metap' > >> +LANGUAGE 'C' STRICT; > >> + > >> +-- > >> +-- bt_page_items() > >> +-- > >> +DROP TYPE bt_page_items_type CASCADE; > >> +CREATE TYPE bt_page_items_type AS ( > >> + itemoffset int4, > >> + ctid tid, > >> + itemlen int4, > >> + nulls bool, > >> + vars bool, > >> + data text > >> +); > >> + > >> +DROP FUNCTION bt_page_items(text, int4); > >> + > >> +CREATE OR REPLACE FUNCTION bt_page_items(text, int4) > >> +RETURNS SETOF bt_page_items_type > >> +AS 'MODULE_PATHNAME', 'bt_page_items' > >> +LANGUAGE 'C' STRICT; > >> + > >> +-- > >> +-- bt_page_stats() > >> +-- > >> +DROP TYPE bt_page_stats_type CASCADE; > >> +CREATE TYPE bt_page_stats_type AS ( > >> + blkno int4, > >> + type char, > >> + live_items int4, > >> + dead_items int4, > >> + avg_item_size float, > >> + page_size int4, > >> + free_size int4, > >> + btpo_prev int4, > >> + btpo_next int4, > >> + btpo int4, > >> + btpo_flags int4 > >> +); > >> + > >> +DROP FUNCTION bt_page_stats(text, int4); > >> + > >> +CREATE OR REPLACE FUNCTION bt_page_stats(text, int4) > >> +RETURNS bt_page_stats_type > >> +AS 'MODULE_PATHNAME', 'bt_page_stats' > >> +LANGUAGE 'C' STRICT; > >> + > >> +-- > >> +-- pg_relpages() > >> +-- > >> +CREATE OR REPLACE FUNCTION pg_relpages(text) > >> +RETURNS int > >> +AS 'MODULE_PATHNAME', 'pg_relpages' > >> +LANGUAGE 'C' STRICT; > >> diff -ruN pgstattuple.orig/test.sh pgstattuple/test.sh > >> --- pgstattuple.orig/test.sh 1970-01-01 09:00:00.000000000 +0900 > >> +++ pgstattuple/test.sh 2006-08-14 10:23:08.000000000 +0900 > >> @@ -0,0 +1,27 @@ > >> +#!/bin/sh > >> + > >> +PGHOME=/home/snaga/pgsql20060814 > >> +export PATH=${PGHOME}/bin:$PATH > >> + > >> +psql -p 9999 pgbench<<EOF > >> +DROP FUNCTION pgstatindex(text); > >> +EOF > >> + > >> +psql -p 9999 -f ${PGHOME}/share/contrib/pgstattuple.sql pgbench > >> + > >> +psql -p 9999 pgbench<<EOF > >> +SELECT * FROM pg_relpages('accounts_pkey'); > >> +\x > >> +SELECT * FROM pgstatindex('accounts_pkey'); > >> +SELECT * FROM bt_metap('accounts_pkey'); > >> +\x > >> +SELECT * FROM bt_page_items('accounts_pkey', 0); > >> +SELECT * FROM bt_page_items('accounts_pkey', 1) limit 20; > >> + > >> +SELECT * FROM bt_page_stats('accounts_pkey', 1); > >> +\x > >> +SELECT * FROM bt_page_stats('accounts_pkey', 1); > >> +SELECT * FROM bt_page_stats('accounts_pkey', 361); > >> +\x > >> +SELECT * FROM bt_page_items('accounts_pkey', 361); > >> +EOF > >> > >> > >> ------------------------------------------------------------------------ > >> > >> pgstattuple README 2002/08/29 Tatsuo Ishii > >> > >> 1. Functions supported: > >> > >> pgstattuple > >> ----------- > >> pgstattuple() returns the relation length, percentage of the "dead" > >> tuples of a relation and other info. This may help users to determine > >> whether vacuum is necessary or not. Here is an example session: > >> > >> test=> \x > >> Expanded display is on. > >> test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc'); > >> -[ RECORD 1 ]------+------- > >> table_len | 458752 > >> tuple_count | 1470 > >> tuple_len | 438896 > >> tuple_percent | 95.67 > >> dead_tuple_count | 11 > >> dead_tuple_len | 3157 > >> dead_tuple_percent | 0.69 > >> free_space | 8932 > >> free_percent | 1.95 > >> > >> Here are explanations for each column: > >> > >> table_len -- physical relation length in bytes > >> tuple_count -- number of live tuples > >> tuple_len -- total tuples length in bytes > >> tuple_percent -- live tuples in % > >> dead_tuple_len -- total dead tuples length in bytes > >> dead_tuple_percent -- dead tuples in % > >> free_space -- free space in bytes > >> free_percent -- free space in % > >> > >> pg_relpages > >> ----------- > >> pg_relpages() returns the number of pages in the relation. > >> > >> pgstatindex > >> ----------- > >> pgstatindex() returns an array showing the information about an index: > >> > >> test=> \x > >> Expanded display is on. > >> test=> SELECT * FROM pgstatindex('pg_cast_oid_index'); > >> -[ RECORD 1 ]------+------ > >> version | 2 > >> tree_level | 0 > >> index_size | 8192 > >> root_block_no | 1 > >> internal_pages | 0 > >> leaf_pages | 1 > >> empty_pages | 0 > >> deleted_pages | 0 > >> avg_leaf_density | 50.27 > >> leaf_fragmentation | 0 > >> > >> bt_metap > >> -------- > >> bt_metap() returns information about the btree index metapage: > >> > >> test=> SELECT * FROM bt_metap('pg_cast_oid_index'); > >> -[ RECORD 1 ]----- > >> magic | 340322 > >> version | 2 > >> root | 1 > >> level | 0 > >> fastroot | 1 > >> fastlevel | 0 > >> > >> bt_page_stats > >> ------------- > >> bt_page_stats() shows information about single btree pages: > >> > >> test=> SELECT * FROM bt_page_stats('pg_cast_oid_index', 1); > >> -[ RECORD 1 ]-+----- > >> blkno | 1 > >> type | l > >> live_items | 256 > >> dead_items | 0 > >> avg_item_size | 12 > >> page_size | 8192 > >> free_size | 4056 > >> btpo_prev | 0 > >> btpo_next | 0 > >> btpo | 0 > >> btpo_flags | 3 > >> > >> bt_page_items > >> ------------- > >> bt_page_items() returns information about specific items on btree pages: > >> > >> test=> SELECT * FROM bt_page_items('pg_cast_oid_index', 1); > >> itemoffset | ctid | itemlen | nulls | vars | data > >> ------------+---------+---------+-------+------+------------- > >> 1 | (0,1) | 12 | f | f | 23 27 00 00 > >> 2 | (0,2) | 12 | f | f | 24 27 00 00 > >> 3 | (0,3) | 12 | f | f | 25 27 00 00 > >> 4 | (0,4) | 12 | f | f | 26 27 00 00 > >> 5 | (0,5) | 12 | f | f | 27 27 00 00 > >> 6 | (0,6) | 12 | f | f | 28 27 00 00 > >> 7 | (0,7) | 12 | f | f | 29 27 00 00 > >> 8 | (0,8) | 12 | f | f | 2a 27 00 00 > >> > >> > >> 2. Installing pgstattuple > >> > >> $ make > >> $ make install > >> $ psql -e -f /usr/local/pgsql/share/contrib/pgstattuple.sql test > >> > >> > >> 3. Using pgstattuple > >> > >> pgstattuple may be called as a relation function and is > >> defined as follows: > >> > >> CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type > >> AS 'MODULE_PATHNAME', 'pgstattuple' > >> LANGUAGE C STRICT; > >> > >> CREATE OR REPLACE FUNCTION pgstattuple(oid) RETURNS pgstattuple_type > >> AS 'MODULE_PATHNAME', 'pgstattuplebyid' > >> LANGUAGE C STRICT; > >> > >> The argument is the relation name (optionally it may be qualified) > >> or the OID of the relation. Note that pgstattuple only returns > >> one row. > >> > >> > >> 4. Notes > >> > >> pgstattuple acquires only a read lock on the relation. So concurrent > >> update may affect the result. > >> > >> pgstattuple judges a tuple is "dead" if HeapTupleSatisfiesNow() > >> returns false. > >> > >> > >> 5. History > >> > >> 2006/06/28 > >> > >> Extended to work against indexes. > > > -- > NAGAYASU Satoshi <nagayasus@nttdata.co.jp> > Phone: +81-3-3523-8122 > $PostgreSQL: pgsql/contrib/pgstattuple/README.pgstattuple.euc_jp,v 1.7 2006/07/06 02:18:07 momjian Exp $ > > pgstattuple README 2002/08/22 ÀаæãÉ× > > 1. ¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë´Ø¿ô > > pgstattuple > ----------- > pgstattuple¤Ï¡¤UPDATE¤äDELETE¤Çºî¤é¤ì¤¿¥ê¥ì¡¼¥·¥ç¥ó¤Î¥´¥ßÎΰè¤ÎÂ礤µ¤ò¡¤ > ¥ê¥ì¡¼¥·¥ç¥ó¼«ÂΤÎʪÍýŪ¤ÊÂ礤µ¤ËÂФ¹¤ë¥Ñ¡¼¥»¥ó¥Æ¡¼¥¸¤ÇÊֵѤ·¤Þ¤¹¡¥¤Ä > ¤Þ¤ê¡¤ÊÖµÑÃͤ¬Â礤±¤ì¤Ð¡¤¤½¤ì¤À¤±¥´¥ß¤â¿¤¤¤Î¤Ç¡¤vacuum¤ò¤«¤±¤ëɬ > Íפ¬¤¢¤ë¤È¤¤¤¦È½ÃǤνõ¤±¤Ë¤Ê¤ë¤ï¤±¤Ç¤¹¡¥¤³¤ì°Ê³°¤Ë¤â¤¤¤í¤¤¤í¤Ê¾ðÊó > ¤¬ÊÖ¤ê¤Þ¤¹¡¥ > pgstattuple() ¤Ï¡¢¥ê¥ì¡¼¥·¥ç¥ó¤ÎŤµ¤ä¡¢¥¿¥×¥ë¤Î"¥´¥ßÎΰè"¤Î³ä¹ç¤Ê¤É¤Î > ¾ðÊó¤òÊֵѤ·¤Þ¤¹¡£¤³¤ì¤é¤Î¾ðÊó¤Ï¡¢vacuum ¤¬É¬Íפ«¤É¤¦¤«¡¢¥æ¡¼¥¶¤¬È½ÃÇ > ¤¹¤ë¤Î¤ËÌòΩ¤Ä¤Ç¤·¤ç¤¦¡£Î㤨¤Ð°Ê²¼¤Î¤è¤¦¤Ê·Á¤Ë¤Ê¤ê¤Þ¤¹¡§ > > test=> \x > Expanded display is on. > test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc'); > -[ RECORD 1 ]------+------- > table_len | 458752 > tuple_count | 1470 > tuple_len | 438896 > tuple_percent | 95.67 > dead_tuple_count | 11 > dead_tuple_len | 3157 > dead_tuple_percent | 0.69 > free_space | 8932 > free_percent | 1.95 > > °Ê²¼¤¬³Æ¹àÌܤÎÆâÍƤǤ¹¡§ > > table_len -- ¥ê¥ì¡¼¥·¥ç¥ó¤ÎʪÍýŪ¤ÊÂ礤µ(¥Ð¥¤¥È) > tuple_count -- ¥¿¥×¥ë¿ô > tuple_len -- ¥¿¥×¥ëĹ¤Î¹ç·×(¥Ð¥¤¥È) > tuple_percent -- ¥¿¥×¥ë¤Î³ä¹ç¡¥table_len¤ËÂФ¹¤ëtuple_len¤ÎÈæΨ¡¥ > dead_tuple_len -- ¥Ç¥Ã¥É¥¿¥×¥ë¿ô > dead_tuple_percent -- ¥Ç¥Ã¥É¥¿¥×¥ë¤Î³ä¹ç¡¥table_len¤ËÂФ¹¤ëtuple_len¤ÎÈæΨ¡¥ > free_space -- ºÆÍøÍѲÄǽ¤ÊÎΰè(¥Ð¥¤¥È) > free_percent -- ºÆÍøÍѲÄǽ¤ÊÎΰ补table_len¤ËÂФ¹¤ëfree_space¤ÎÈæΨ¡¥ > > pg_relpages > ----------- > pg_relpages() ¤Ï¥ê¥ì¡¼¥·¥ç¥ó¤Î¥Ú¡¼¥¸¿ô¤òÊֵѤ·¤Þ¤¹¡¥ > > pgstatindex > ----------- > pgstatindex() ¤Ï¥¤¥ó¥Ç¥Ã¥¯¥¹¤Ë´Ø¤¹¤ë¾ðÊó¤òÊֵѤ·¤Þ¤¹¡§ > > test=> \x > Expanded display is on. > test=> SELECT * FROM pgstatindex('pg_cast_oid_index'); > -[ RECORD 1 ]------+------ > version | 2 > tree_level | 0 > index_size | 8192 > root_block_no | 1 > internal_pages | 0 > leaf_pages | 1 > empty_pages | 0 > deleted_pages | 0 > avg_leaf_density | 50.27 > leaf_fragmentation | 0 > > bt_metap > -------- > bt_metap() ¤Ïbtree¥¤¥ó¥Ç¥Ã¥¯¥¹¤Î¥á¥¿¥Ú¡¼¥¸¤Ë´Ø¤¹¤ë¾ðÊó¤òÊֵѤ·¤Þ¤¹¡§ > > test=> SELECT * FROM bt_metap('pg_cast_oid_index'); > -[ RECORD 1 ]----- > magic | 340322 > version | 2 > root | 1 > level | 0 > fastroot | 1 > fastlevel | 0 > > bt_page_stats > ------------- > bt_page_stats() ¤Ï¡¢btree¤Îñ°ì¤Î¥Ú¡¼¥¸¤Ë´Ø¤¹¤ë¾ðÊó¤òɽ¼¨¤·¤Þ¤¹¡§ > > test=> SELECT * FROM bt_page_stats('pg_cast_oid_index', 1); > -[ RECORD 1 ]-+----- > blkno | 1 > type | l > live_items | 256 > dead_items | 0 > avg_item_size | 12 > page_size | 8192 > free_size | 4056 > btpo_prev | 0 > btpo_next | 0 > btpo | 0 > btpo_flags | 3 > > bt_page_items > ------------- > bt_page_items() ¤Ï¡¢³Æbtree¥Ú¡¼¥¸¤Î¸ÄÊ̤Υ¢¥¤¥Æ¥à¤Ë´Ø¤¹¤ë¾ðÊó¤òɽ¼¨¤·¤Þ¤¹¡§ > > test=> SELECT * FROM bt_page_items('pg_cast_oid_index', 1); > itemoffset | ctid | itemlen | nulls | vars | data > ------------+---------+---------+-------+------+------------- > 1 | (0,1) | 12 | f | f | 23 27 00 00 > 2 | (0,2) | 12 | f | f | 24 27 00 00 > 3 | (0,3) | 12 | f | f | 25 27 00 00 > 4 | (0,4) | 12 | f | f | 26 27 00 00 > 5 | (0,5) | 12 | f | f | 27 27 00 00 > 6 | (0,6) | 12 | f | f | 28 27 00 00 > 7 | (0,7) | 12 | f | f | 29 27 00 00 > 8 | (0,8) | 12 | f | f | 2a 27 00 00 > > > 2. pgstattuple¤Î¥¤¥ó¥¹¥È¡¼¥ë > > PostgreSQL¤¬/usr/local/pgsql¤Ë¥¤¥ó¥¹¥È¡¼¥ëºÑ¤Ç¤¢¤ê¡¤test¥Ç¡¼¥¿¥Ù¡¼ > ¥¹¤Ëpgstattuple¤ò¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¾ì¹ç¤Î¼ê½ç¤ò¼¨¤·¤Þ¤¹¡¥ > > $ make > $ make install > > ¥æ¡¼¥¶ÄêµÁ´Ø¿ô¤òÅÐÏ¿¤·¤Þ¤¹¡¥ > > $ psql -e -f /usr/local/pgsql/share/contrib/pgstattuple.sql test > > > 3. pgstattuple¤Î»È¤¤Êý > > pgstattuple¤Î¸Æ¤Ó½Ð¤··Á¼°¤Ï°Ê²¼¤Ç¤¹¡¥ > > CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type > AS 'MODULE_PATHNAME', 'pgstattuple' > LANGUAGE C STRICT; > > Âè°ì°ú¿ô: ¥ê¥ì¡¼¥·¥ç¥ó̾ > > ´Ø¿ô¤ÎÌá¤ê¤Ïpgstattuple_type·¿¤Ç¤¹¡¥ > > pgstattuple¤Ï¥ê¥ì¡¼¥·¥ç¥ó¤ËAccessShareLock¤·¤«¤«¤±¤Ê¤¤¤Î¤Ç¡¤ > pgstattuple ¤ò¼Â¹ÔÃæ¤Ë³ºÅö¥ê¥ì¡¼¥·¥ç¥ó¤Ë¹¹¿·¤äºï½ü¤¬È¯À¸¤¹¤ë¤È¡¤Àµ¤·¤¯ > ¤Ê¤¤·ë²Ì¤òÊÖ¤¹²ÄǽÀ¤¬¤¢¤ê¤Þ¤¹¡¥ > > pgstattuple¤¬¥¿¥×¥ë¤ò¡Ö¥´¥ß¡×¤ÈȽÃǤ¹¤ë´ð½à¤Ï¡¤ > HeapTupleSatisfiesNow()¤¬µ¶¤òÊÖ¤·¤¿¤È¤¤Ç¤¹¡¥ > > 4. pgstattuple¤Î¥é¥¤¥»¥ó¥¹¾ò·ï¤Ë¤Ä¤¤¤Æ > > pgstattuple.c¤ÎËÁƬ¤Ë½ñ¤¤¤Æ¤¢¤ëÄ̤ê¤Ç¤¹¡¥¤Þ¤¿¡¤pgstattuple ¤Ï´°Á´¤Ë̵ÊÝ > ¾Ú¤Ç¤¹¡¥pgstattuple ¤ò»ÈÍѤ·¤¿¤³¤È¤Ë¤è¤Ã¤ÆÀ¸¤¸¤ë¤¤¤«¤Ê¤ë·ë²Ì¤Ë´Ø¤·¤Æ > ¤âÀÕǤ¤òÉ餤¤Þ¤»¤ó¡¥ > > 5. ²þÄûÍúÎò > > 2006/06/28 > > ¥¤¥ó¥Ç¥Ã¥¯¥¹¤ËÂФ·¤Æ¤âÆ°ºî¤¹¤ë¤è¤¦¤Ë³ÈÄ¥¡£ > > 2002/09/04 > > SRFÊѹ¹¤Ëȼ¤¤¡¤Tom Lane ¤¬½¤Àµ¥¤¥ó¥¿¡¼¥Õ¥§¥¤¥¹¤Î½¤Àµ¤ò¹Ô¤Ã¤¿¡¥ > ¤½¤Î¤³¤È¤ò¤³¤ÎREADME¤Ë¤âÈ¿±Ç¡¥ > > 2002/08/23 > > SRF(Set Returning Function)¤ò»È¤Ã¤Æ7.3ÍѤ˽ñ¤´¹¤¨¡¥ > > 2001/12/20 Tom Lane¤Ë¤è¤ë½¤Àµ > > Fix pgstattuple to acquire a read lock on the target table. This > prevents embarassments such as having the table dropped or truncated > partway through the scan. Also, fix free space calculation to include > pages that currently contain no tuples. > > 2001/10/01 PostgreSQL 7.2 ÍÑcontrib module¤ËÅÐÏ¿ > > 2001/08/30 pgstattuple ¥Ð¡¼¥¸¥ç¥ó 0.1¥ê¥ê¡¼¥¹ > > -- Adjust this setting to control where the objects get created. > SET search_path = public; > > DROP FUNCTION pgstattuple(oid); > > DROP FUNCTION pgstattuple(text); > > DROP TYPE pgstattuple_type; > > DROP FUNCTION pgstatindex(text); > DROP FUNCTION bt_metap(text); > DROP FUNCTION bt_page_items(text, int4); > DROP FUNCTION bt_page_stats(text, int4); > DROP FUNCTION pg_relpages(text); > > DROP TYPE pgstatindex_type; > DROP TYPE bt_metap_type; > DROP TYPE bt_page_items_type; > DROP TYPE bt_page_stats_type; -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
pgsql-patches by date: